From: William F. <wsf...@us...> - 2004-07-04 07:31:02
|
Update of /cvsroot/swig/SWIG/Doc/Manual In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3505 Modified Files: Java.html Log Message: exception handling notes added Index: Java.html =================================================================== RCS file: /cvsroot/swig/SWIG/Doc/Manual/Java.html,v retrieving revision 1.28 retrieving revision 1.29 diff -C2 -d -r1.28 -r1.29 *** Java.html 27 Jun 2004 21:11:50 -0000 1.28 --- Java.html 4 Jul 2004 07:30:50 -0000 1.29 *************** *** 86,90 **** <li><a href="#n55">C/C++ helper functions</a> <li><a href="#n56">Class extension with %extend</a> ! <li><a href="#n57">Exception handling with %exception</a> <li><a href="#n58">Method access with %javamethodmodifiers</a> </ul> --- 86,90 ---- <li><a href="#n55">C/C++ helper functions</a> <li><a href="#n56">Class extension with %extend</a> ! <li><a href="#n57">Exception handling with %exception and %javaexception</a> <li><a href="#n58">Method access with %javamethodmodifiers</a> </ul> *************** *** 102,105 **** --- 102,106 ---- <li><a href="#n67">What is a typemap?</a> <li><a href="#n68">Typemaps for mapping C/C++ types to Java types</a> + <li><a href="#n681">Additional Java typemap attributes</a> <li><a href="#n69">Java special variables</a> <li><a href="#n70">Typemaps for both C and C++ compilation</a> *************** *** 110,113 **** --- 111,115 ---- <ul> <li><a href="#n74">Simpler Java enums for enums without initializers</a> + <li><a href="#n741">Handling C++ exception specifications as Java exceptions</a> <li><a href="#n75">Converting Java String arrays to char ** </a> <li><a href="#n76">Expanding a Java object to multiple arguments</a> *************** *** 2897,2901 **** <a name="exception_handling"></a> ! <a name="n57"></a><H3>17.6.3 Exception handling with %exception</H3> --- 2899,2903 ---- <a name="exception_handling"></a> ! <a name="n57"></a><H3>17.6.3 Exception handling with %exception and %javaexception</H3> *************** *** 2903,2906 **** --- 2905,2909 ---- exception. To do this, you can use the <tt>%exception</tt> directive. The <tt>%exception</tt> directive simply lets you rewrite part of the generated wrapper code to include an error check. + It is detailed in full in the <a href="Customization.html#exception">Exception handling with %exception</a> section. <p> *************** *** 2981,2987 **** } ! class Base { public: ! Foo *getitem(int index); // Exception handler added ... }; --- 2984,3015 ---- } ! class FooClass { public: ! FooClass *getitem(int index); // Might throw std::out_of_range exception ! ... ! }; ! </pre> ! </blockquote> ! ! In the example above, <tt>java.lang.Exception</tt> is a checked exception class and so ought to be declared in the throws clause of <tt>getitem</tt>. ! Classes can be specified for adding to the throws clause using <tt>%javaexception(classes)</tt> instead of <tt>%exception</tt>, ! where <tt>classes</tt> is a string containing one or more comma separated Java classes. ! The <tt>%nojavaexception</tt> feature is the equivalent to <tt>%noexception</tt> and clears previously declared exception handlers. ! ! <blockquote> ! <pre> ! %javaexception("java.lang.Exception") getitem { ! try { ! $action ! } catch (std::out_of_range &e) { ! jclass clazz = jenv->FindClass("java/lang/Exception"); ! jenv->ThrowNew(clazz, "Range error"); ! return $null; ! } ! } ! ! class FooClass { ! public: ! FooClass *getitem(int index); // Might throw std::out_of_range exception ... }; *************** *** 2989,2992 **** --- 3017,3033 ---- </blockquote> + The generated proxy method now generates a throws clause containing <tt>java.lang.Exception</tt>: + + <blockquote> + <pre> + public class FooClass { + ... + public FooClass getitem(int index) throws java.lang.Exception { ... } + ... + } + </pre> + </blockquote> + + The examples above first use the C JNI calling syntax then the C++ JNI calling syntax. The C++ calling syntax will not compile as C and also visa versa. It is however possible to write JNI calls which will compile under both C and C++ and is covered in the <a href="#typemaps_for_c_and_c++">Typemaps for both C and C++ compilation</a> section. *************** *** 2995,2998 **** --- 3036,3040 ---- The language-independent <tt>exception.i</tt> library file can also be used to raise exceptions. See the <a href="Library.html">SWIG Library</a> chapter. + The typemap example <a href="#exception_typemap">Handling C++ exception specifications as Java exceptions</a> provides further exception handling capabilities. <a name="method_access"></a> *************** *** 3858,3861 **** --- 3900,3928 ---- </table> + <a name="typemap_attributes"></a> + <a name="n681"></a><H3>17.8.5 Java typemap attributes</H3> + There is an additional typemap attribute that the Java module supports. + This is the 'throws' attribute. + The throws attribute is optional and specified after the typemap name and contains one or more comma separated classes for adding to the throws clause for any methods that use that typemap. + It is analogous to the <a href="#exception_handling">%javaexception</a> feature's throws attribute. + + <blockquote> + <pre> + %typemap(typemapname, throws="ExceptionClass1, ExceptionClass2") type { ... } + </pre> + </blockquote> + + The attribute is necessary for supporting Java checked exceptions and can be added to just about any typemap. + The list of typemaps include all the C/C++ (JNI) typemaps in the "<a href="Typemaps.html">Typemaps</a>" chapter and the + Java specific typemaps listed in <a href="#typemaps_c_to_java_types">the previous section</a>, barring + the "jni", "jtype" and "jstype" typemaps as they could never contain code to throw an exception. + + <p/> + + The throws clause is generated for the proxy method as well as the JNI method in the JNI intermediary class. + If a method uses more than one typemap and each of those typemaps have classes specified in the throws clause, + the union of the exception classes is added to the throws clause ensuring there are no duplicate classes. + See the <a href="#nan_exception_typemap">NaN exception example</a> for further usage. + <a name="special_variables"></a> <a name="n69"></a><H3>17.8.5 Java special variables</H3> *************** *** 4397,4401 **** public static HairType getHair() { return HairType.class.getEnumConstants()[exampleJNI.getHair()]; ! } </pre> </blockquote> --- 4464,4468 ---- public static HairType getHair() { return HairType.class.getEnumConstants()[exampleJNI.getHair()]; ! }/ </pre> </blockquote> *************** *** 4414,4417 **** --- 4481,4692 ---- + <a name="exception_typemap"></a> + <a name="n741"></a><H3>17.9.2 Handling C++ exception specifications as Java exceptions</H3> + + This example demonstrates various ways in which C++ exceptions can be tailored and converted into Java exceptions. + Let's consider a simple file class <tt>SimpleFile</tt> and an exception class <tt>FileException</tt> which it may throw on error: + + <blockquote> + <pre> + %include "std_string.i" // for std::string typemaps + #include <string> + + class FileException { + std::string message; + public: + FileException(const std::string& msg) : message(msg) {} + std::string what() { + return message; + } + }; + + class SimpleFile { + std::string filename; + public: + SimpleFile(const std::string& filename) : filename(filename) {} + void open() throw(FileException) { + ... + } + }; + </pre> + </blockquote> + + As the <tt>open</tt> method has a C++ exception specification, SWIG will parse this and know that the method can throw an exception. + The <a href="Typemaps.html#throws_typemap">"throws" typemap</a> is then used when SWIG encounters an exception specification. + The default generic "throws" typemap looks like this: + + <blockquote> + <pre> + %typemap(throws) SWIGTYPE, SWIGTYPE &, SWIGTYPE *, SWIGTYPE [ANY] %{ + SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "C++ $1_type exception thrown"); + return $null; + %} + </pre> + </blockquote> + + Basically SWIG will generate a C++ try catch block and the body of the "throws" typemap constitutes the catch block. + The above typemap calls a SWIG supplied method which throws a <tt>java.lang.RuntimeException</tt>. + This exception class is a runtime exception and therefore not a checked exception. + If, however, we wanted to throw a checked exception, say <tt>java.io.IOException</tt>, then we could use the following typemap: + + <blockquote> + <pre> + %typemap(throws, throws="java.io.IOException") FileException { + jclass excep = jenv->FindClass("java/io/IOException"); + if (excep) + jenv->ThrowNew(excep, $1.what().c_str()); + return $null; + } + </pre> + </blockquote> + + Note that this typemap uses the 'throws' <a href="#typemap_attributes">typemap attribute</a> to ensure a throws clause is generated. + The generated proxy method then specifies the checked exception by containing <tt>java.io.IOException</tt> in the throws clause: + + <blockquote> + <pre> + public class SimpleFile { + ... + public void open() throws java.io.IOException { ... } + } + </pre> + </blockquote> + + Lastly, if you don't want to map your C++ exception into one of the standard Java exceptions, the C++ class can be wrapped and turned into a custom Java exception class. + If we go back to our example, the first thing we must do is get SWIG to wrap <tt>FileException</tt> and ensure that it derives from <tt>java.lang.Exception</tt>. + Additionally, we might want to override the <tt>java.lang.Exception.getMessage()</tt> method. + The typemaps to use then are as follows: + + <blockquote> + <pre> + %typemap(javabase) FileException "java.lang.Exception"; + %typemap(javacode) FileException %{ + public String getMessage() { + return what(); + } + %} + </pre> + </blockquote> + + This generates: + <blockquote> + <pre> + public class FileException extends java.lang.Exception { + ... + public String getMessage() { + return what(); + } + + public FileException(String msg) { ... } + + public String what() { + return exampleJNI.FileException_what(swigCPtr); + } + } + </pre> + </blockquote> + + We could alternatively have used <tt>%rename</tt> to rename <tt>what()</tt> into <tt>getMessage()</tt>. + + + <a name="nan_exception_typemap"></a> + <a name="n75"></a><H3>17.9.2 NaN Exception - exception handling for a particular type</H3> + A Java exception can be thrown from any Java or JNI code. + Therefore, as most typemaps contain either Java or JNI code, just about any typemap could throw an exception. + The following example demonstrates exception handling on a type by type basis by checking for 'Not a number' (NaN) whenever a parameter of type <tt>float</tt> is wrapped. + <p> + Consider the following C++ code: + + <blockquote> + <pre> + bool calculate(float first, float second); + </pre> + </blockquote> + + To validate every <tt>float</tt> being passed to C++, we could preceed the code being wrapped by the following typemap which throws a runtime exception whenever the <tt>float</tt> is 'Not a Number': + + <blockquote> + <pre> + %module example + %typemap(javain) float "$module.CheckForNaN($javainput)" + %pragma(java) modulecode=%{ + /** Simply returns the input value unless it is not a number, whereupon an exception is thrown. */ + static protected float CheckForNaN(float num) { + if (Float.isNaN(num)) + throw new RuntimeException("Not a number"); + return num; + } + %} + </pre> + </blockquote> + + Note that the <tt>CheckForNaN</tt> support method has been added to the module class using the <tt>modulecode</tt> pragma. + The following shows the generated code of interest: + + <blockquote> + <pre> + public class example { + ... + + /** Simply returns the input value unless it is not a number, whereupon an exception is thrown. */ + static protected float CheckForNaN(float num) { + if (Float.isNaN(num)) + throw new RuntimeException("Not a number"); + return num; + } + + public static boolean calculate(float first, float second) { + return exampleJNI.calculate(example.CheckForNaN(first), example.CheckForNaN(second)); + } + } + </pre> + </blockquote> + + Note that the "javain" typemap is used for every occurrence of a <tt>float</tt> being used as an input. + Of course, we could have targetted the typemap at a particular parameter by using <tt>float first</tt>, say, instead of just <tt>float</tt>. + If we decide that what we actually want is a checked exception instead of a runtime exception, we can change this easily enough. + The proxy method that uses <tt>float</tt> as an input, must then add the exception class to the throws clause. + SWIG can handle this as it supports the 'throws' <a href="#typemap_attributes">typemap attribute</a> for specifying classes for the throws clause. + Thus we can modify the pragma and the typemap for the throws clause: + + <blockquote> + <pre> + %typemap(javain, throws="java.lang.Exception") float "$module.CheckForNaN($javainput)" + %pragma(java) modulecode=%{ + /** Simply returns the input value unless it is not a number, whereupon an exception is thrown. */ + static protected float CheckForNaN(float num) throws java.lang.Exception { + if (Float.isNaN(num)) + throw new RuntimeException("Not a number"); + return num; + } + %} + </pre> + </blockquote> + + The <tt>calculate</tt> method now has a throws clause and even though the typemap is used twice for both <tt>float first</tt> and <tt>float second</tt>, + the throws clause contains a single instance of <tt>java.lang.Exception</tt>: + + <blockquote> + <pre> + public class example { + ... + + /** Simply returns the input value unless it is not a number, whereupon an exception is thrown. */ + static protected float CheckForNaN(float num) throws java.lang.Exception { + if (Float.isNaN(num)) + throw new RuntimeException("Not a number"); + return num; + } + + public static boolean calculate(float first, float second) throws java.lang.Exception { + return exampleJNI.calculate(example.CheckForNaN(first), example.CheckForNaN(second)); + } + } + </pre> + </blockquote> + + If we were a martyr to the JNI cause, we could replace the succinct code within the "javain" typemap with a few pages of JNI code. + If we had, we would have put it in the "in" typemap which, like all JNI and Java typemaps, also supports the 'throws' attribute. + <a name="converting_java_string_arrays"></a> <a name="n75"></a><H3>17.9.2 Converting Java String arrays to char ** </H3> |