From: <wsf...@us...> - 2007-04-17 22:44:36
|
Revision: 9677 http://swig.svn.sourceforge.net/swig/?rev=9677&view=rev Author: wsfulton Date: 2007-04-17 15:44:33 -0700 (Tue, 17 Apr 2007) Log Message: ----------- Add in pre, post and pgcppname attributes for the javain typemap Modified Paths: -------------- trunk/Doc/Manual/Java.html trunk/Source/Modules/java.cxx Modified: trunk/Doc/Manual/Java.html =================================================================== --- trunk/Doc/Manual/Java.html 2007-04-17 22:34:49 UTC (rev 9676) +++ trunk/Doc/Manual/Java.html 2007-04-17 22:44:33 UTC (rev 9677) @@ -126,6 +126,7 @@ <li><a href="#struct_pointer_pointer">Struct pointer to pointer</a> <li><a href="#java_memory_management_member_variables">Memory management when returning references to member variables</a> <li><a href="#java_memory_management_objects">Memory management for objects passed to the C++ layer</a> +<li><a href="#java_date_marshalling">Date marshalling using the javain typemap and associated attributes</a> </ul> <li><a href="#java_directors_faq">Living with Java Directors</a> <li><a href="#odds_ends">Odds and ends</a> @@ -1887,7 +1888,7 @@ <pre> %module example %{ -#include "pair.h" +#include <utility> %} template<class T1, class T2> @@ -4722,8 +4723,11 @@ <p> -There is an additional typemap attribute that the Java module supports. -This is the 'throws' attribute. +There are a few additional typemap attributes that the Java module supports. +</p> + +<p> +The first of these 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. </p> @@ -4749,9 +4753,18 @@ </p> <p> -The "jnitype" typemap has the 'nopgcpp' attribute which can be used to suppress the generation of the <a href="java_pgcpp">premature garbage collection prevention parameter</a>. +The "jnitype" typemap has the optional 'nopgcpp' attribute which can be used to suppress the generation of the <a href="java_pgcpp">premature garbage collection prevention parameter</a>. </p> +<p> +The "javain" typemap has the optional 'pre', 'post' and 'pgcppname' attributes. These are used for generating code before and after the JNI call in the proxy class or module class. The 'pre' attribute contains code that is generated before the JNI call and the 'post' attribute contains code generated after the JNI call. The 'pgcppname' attribute is used to change the <a href="java_pgcpp">premature garbage collection prevention parameter</a> name passed to the JNI function. This is sometimes needed when the 'pre' typemap creates a temporary variable which is then passed to the JNI function. +</p> + +<p> +<a name="java_constructor_helper_function"></a> +Note that when the 'pre' or 'post' attributes are specified and the associated type is used in a constructor, a constructor helper function is generated. This is necessary as the Java proxy constructor wrapper makes a call to a support constructor using a <i>this</i> call. In Java the <i>this</i> call must be the first statement in the constructor body. The constructor body thus calls the helper function and the helper function instead makes the JNI call, ensuring the 'pre' code is called before the JNI call is made. There is a <a href="#java_date_marshalling">Date marshalling</a> example showing 'pre', 'post' and 'pgcppname' attributes in action. +</p> + <H3><a name="special_variables"></a>20.8.7 Java special variables</H3> @@ -5631,6 +5644,43 @@ <p> 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 targeted the typemap at a particular parameter by using <tt>float first</tt>, say, instead of just <tt>float</tt>. +</p> + +<p> +The exception checking could alternatively have been placed into the 'pre' attribute that the "javain" typemap supports. +The "javain" typemap above could be replaced with the following: +</p> + +<div class="code"> +<pre> +%typemap(javain, pre=" $module.CheckForNaN($javainput);") float "$javainput" +</pre> +</div> + +<p> +which would modify the <tt>calculate</tt> function to instead be generated as: +</p> + +<div class="code"> +<pre> +public class example { + ... + public static boolean calculate(float first, float second) { + example.CheckForNaN(first); + example.CheckForNaN(second); + { + return exampleJNI.calculate(first, second); + } + } +} +</pre> +</div> + +<p> +See the <a href="#java_date_marshalling">Date marshalling example</a> for an example using further "javain" typemap attributes. +</p> + +<p> 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. @@ -6754,7 +6804,183 @@ </div> +<H3><a name="java_date_marshalling"></a>20.9.13 Date marshalling using the javain typemap and associated attributes</H3> + +<p> +The <a href="#nan_exception_typemap">NaN Exception example</a> is a simple example of the "javain" typemap and its 'pre' attribute. +This example demonstrates how a C++ date class, say <tt>CDate</tt>, can be mapped onto the standard Java date class, +<tt>java.util.GregorianCalendar</tt> by using the 'pre', 'post' and 'pgcppname' attributes of the "javain" typemap. +The idea is that the <tt>GregorianCalendar</tt> is used wherever the C++ API uses a <tt>CDate</tt>. +Let's assume the code being wrapped is as follows: +</p> + +<div class="code"> +<pre> +class CDate { +public: + CDate(int year, int month, int day); + int getYear(); + int getMonth(); + int getDay(); + ... +}; +struct Action { + static int doSomething(const CDate &dateIn, CDate &dateOut); + Action(const CDate &date, CDate &dateOut); +}; +</pre> +</div> + +<p> +Note that <tt>dateIn</tt> is const and therefore read only and <tt>dateOut</tt> is a non-const output type. +</p> + +<p> +First let's look at the code that is generated by default, where the Java proxy class <tt>CDate</tt> is used in the proxy interface: +</p> + +<div class="code"> +<pre> +public class Action { + ... + public static int doSomething(CDate dateIn, CDate dateOut) { + return exampleJNI.Action_doSomething(CDate.getCPtr(dateIn), dateIn, + CDate.getCPtr(dateOut), dateOut); + } + + public Action(CDate date, CDate dateOut) { + this(exampleJNI.new_Action(CDate.getCPtr(date), date, + CDate.getCPtr(dateOut), dateOut), true); + } +} +</pre> +</div> + +<p> +The <tt>CDate &</tt> and <tt>const CDate &</tt> Java code is generated from the following two default typemaps: +</p> + +<div class="code"> +<pre> +%typemap(jstype) SWIGTYPE & "$javaclassname" +%typemap(javain) SWIGTYPE & "$javaclassname.getCPtr($javainput)" +</pre> +</div> + +<p> +where '$javaclassname' is translated into the proxy class name, <tt>CDate</tt> and '$javainput' is translated into the name of the parameter, eg <tt>dateIn</tt>. +From Java, the intention is then to call into a modifed API with something like: +</p> + +<div class="code"> +<pre> +java.util.GregorianCalendar calendarIn = + new java.util.GregorianCalendar(2011, java.util.Calendar.APRIL, 13, 0, 0, 0); +java.util.GregorianCalendar calendarOut = new java.util.GregorianCalendar(); + +// Note in calls below, calendarIn remains unchanged and calendarOut +// is set to a new value by the C++ call +Action.doSomething(calendarIn, calendarOut); +Action action = new Action(calendarIn, calendarOut); +</pre> +</div> + +<p> +To achieve this mapping, we need to alter the default code generation slightly so that at the Java layer, +a <tt>GregorianCalendar</tt> is converted into a <tt>CDate</tt>. +The JNI intermediary layer will still take a pointer to the underlying <tt>CDate</tt> class. +The typemaps to achieve this are shown below. +</p> + +<div class="code"> +<pre> +%typemap(jstype) const CDate& "java.util.GregorianCalendar" +%typemap(javain, + pre=" CDate temp$javainput = new CDate($javainput.get(java.util.Calendar.YEAR), " + "$javainput.get(java.util.Calendar.MONTH), $javainput.get(java.util.Calendar.DATE));", + pgcppname="temp$javainput") const CDate & + "$javaclassname.getCPtr(temp$javainput)" + +%typemap(jstype) CDate& "java.util.Calendar" +%typemap(javain, + pre=" CDate temp$javainput = new CDate($javainput.get(java.util.Calendar.YEAR), " + "$javainput.get(java.util.Calendar.MONTH), $javainput.get(java.util.Calendar.DATE));", + post=" $javainput.set(temp$javainput.getYear(), temp$javainput.getMonth(), " + "temp$javainput.getDay(), 0, 0, 0);", + pgcppname="temp$javainput") CDate & + "$javaclassname.getCPtr(temp$javainput)" +</pre> +</div> + +<p> +The resulting generated proxy code in the <tt>Action</tt> class follows: + </p> + +<div class="code"> +<pre> +public class Action { + ... + public static int doSomething(java.util.GregorianCalendar dateIn, + java.util.Calendar dateOut) { + CDate tempdateIn = new CDate(dateIn.get(java.util.Calendar.YEAR), + dateIn.get(java.util.Calendar.MONTH), + dateIn.get(java.util.Calendar.DATE)); + CDate tempdateOut = new CDate(dateOut.get(java.util.Calendar.YEAR), + dateOut.get(java.util.Calendar.MONTH), + dateOut.get(java.util.Calendar.DATE)); + try { + return exampleJNI.Action_doSomething(CDate.getCPtr(tempdateIn), tempdateIn, + CDate.getCPtr(tempdateOut), tempdateOut); + } finally { + dateOut.set(tempdateOut.getYear(), tempdateOut.getMonth(), tempdateOut.getDay(), 0, 0, 0); + } + } + + static private long SwigConstructAction(java.util.GregorianCalendar date, + java.util.Calendar dateOut) { + CDate tempdate = new CDate(date.get(java.util.Calendar.YEAR), + date.get(java.util.Calendar.MONTH), + date.get(java.util.Calendar.DATE)); + CDate tempdateOut = new CDate(dateOut.get(java.util.Calendar.YEAR), + dateOut.get(java.util.Calendar.MONTH), + dateOut.get(java.util.Calendar.DATE)); + try { + return exampleJNI.new_Action(CDate.getCPtr(tempdate), tempdate, + CDate.getCPtr(tempdateOut), tempdateOut); + } finally { + dateOut.set(tempdateOut.getYear(), tempdateOut.getMonth(), tempdateOut.getDay(), 0, 0, 0); + } + } + + public Action(java.util.GregorianCalendar date, java.util.Calendar dateOut) { + this(Action.SwigConstructAction(date, dateOut), true); + } +} +</pre> +</div> + +<p> +A few things to note: +</p> +<ul> + <li> The "javatype" typemap has changed the parameter type to <tt>java.util.GregorianCalendar</tt> or <tt>java.util.Calendar</tt> instead of the default generated <tt>CDate</tt> proxy. + <li> The code in the 'pre' attribute appears before the JNI call (<tt>exampleJNI.new_Action</tt> / <tt>exampleJNI.Action_doSomething</tt>). + <li> The code in the 'post' attribute appears after the JNI call. + <li> A try .. finally block is generated with the JNI call in the try block and 'post' code in the finally block. + The alternative of just using a temporary variable for the return value from the JNI call and the 'post' code being generated before the + return statement is not possible given that the JNI call is in one line and comes from the "javaout" typemap. + <li> The temporary variables in the "javain" typemaps are called <tt>temp$javain</tt>, where "$javain" is replaced with the parameter name. + "$javain" is used to mangle the variable name so that more than one <tt>CDate &</tt> type can be used as a parameter in a method, otherwise two or + more local variables with the same name would be generated. + <li> The use of the "javain" typemap causes a constructor helper function (<tt>SwigConstructAction</tt>) to be generated. + This allows Java code to be called before the JNI call and is required as the Java compiler won't compile code inserted before the 'this' call. + <li> The 'pgcppname' attribute is used to modify the object being passed as the <a href="#java_pgcpp">premature garbage collection prevention parameter</a> (the 2nd and 4th parameters in the JNI calls). +</ul> + + + + <H2><a name="java_directors_faq"></a>20.10 Living with Java Directors</H2> Modified: trunk/Source/Modules/java.cxx =================================================================== --- trunk/Source/Modules/java.cxx 2007-04-17 22:34:49 UTC (rev 9676) +++ trunk/Source/Modules/java.cxx 2007-04-17 22:44:33 UTC (rev 9677) @@ -1864,6 +1864,8 @@ String *return_type = NewString(""); String *function_code = NewString(""); bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); if (!proxy_flag) return; @@ -1908,7 +1910,7 @@ /* Start generating the proxy function */ const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); - methodmods = methodmods ? methodmods : (!is_public(n) ? protected_string : public_string); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); Printf(function_code, " %s ", methodmods); if (static_flag) Printf(function_code, "static "); @@ -1977,6 +1979,22 @@ addThrows(n, "tmap:javain", p); substituteClassname(pt, tm); Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } Printv(imcall, tm, NIL); } else { Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); @@ -1988,8 +2006,17 @@ gencomma = 2; Printf(function_code, "%s %s", param_type, arg); - if (prematureGarbageCollectionPreventionParameter(pt, p)) - Printf(imcall, ", %s", arg); + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } Delete(arg); Delete(param_type); @@ -2003,6 +2030,23 @@ // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in proxy class) if ((tm = Swig_typemap_lookup_new("javaout", n, "", 0))) { addThrows(n, "tmap:javaout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } if (GetFlag(n, "feature:new")) Replaceall(tm, "$owner", "true"); else @@ -2040,6 +2084,8 @@ Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); Printv(proxy_class_code, function_code, NIL); + Delete(pre_code); + Delete(post_code); Delete(function_code); Delete(return_type); Delete(imcall); @@ -2056,6 +2102,11 @@ Parm *p; int i; String *function_code = NewString(""); + String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the javain typemap has code in the pre or post attributes + String *helper_args = NewString(""); + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *im_return_type = NewString(""); bool feature_director = (parentNode(n) && Swig_directorclass(n)); Language::constructorHandler(n); @@ -2070,8 +2121,14 @@ String *imcall = NewString(""); const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); - methodmods = methodmods ? methodmods : (!is_public(n) ? protected_string : public_string); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + tm = Getattr(n, "tmap:jtype"); // typemaps were attached earlier to the node + Printf(im_return_type, "%s", tm); + Printf(function_code, " %s %s(", methodmods, proxy_class_name); + Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + Printv(imcall, imclass_name, ".", mangled_overname, "(", NIL); /* Attach the non-standard typemaps to the parameter list */ @@ -2120,19 +2177,49 @@ addThrows(n, "tmap:javain", p); substituteClassname(pt, tm); Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } Printv(imcall, tm, NIL); } else { Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); } /* Add parameter to proxy function */ - if (gencomma) + if (gencomma) { Printf(function_code, ", "); + Printf(helper_code, ", "); + Printf(helper_args, ", "); + } Printf(function_code, "%s %s", param_type, arg); + Printf(helper_code, "%s %s", param_type, arg); + Printf(helper_args, "%s", arg); ++gencomma; - if (prematureGarbageCollectionPreventionParameter(pt, p)) - Printf(imcall, ", %s", arg); + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } Delete(arg); Delete(param_type); @@ -2142,6 +2229,7 @@ Printf(imcall, ")"); Printf(function_code, ")"); + Printf(helper_code, ")"); generateThrowsClause(n, function_code); /* Insert the javaconstruct typemap, doing the replacement for $directorconnect, as needed */ @@ -2166,10 +2254,36 @@ Printv(function_code, " ", construct_tm, "\n", NIL); } - Replaceall(function_code, "$imcall", imcall); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + generateThrowsClause(n, helper_code); + Printf(helper_code, " {\n"); + if (is_pre_code) { + Printv(helper_code, pre_code, "\n", NIL); + } + if (is_post_code) { + Printf(helper_code, " try {\n"); + Printv(helper_code, " return ", imcall, ";\n", NIL); + Printv(helper_code, " } finally {\n", post_code, "\n }", NIL); + } else { + Printv(helper_code, " return ", imcall, ";", NIL); + } + Printf(helper_code, "\n }\n"); + String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", proxy_class_name, proxy_class_name, helper_args); + Printv(proxy_class_code, helper_code, "\n", NIL); + Replaceall(function_code, "$imcall", helper_name); + Delete(helper_name); + } else { + Replaceall(function_code, "$imcall", imcall); + } Printv(proxy_class_code, function_code, "\n", NIL); + Delete(helper_args); + Delete(im_return_type); + Delete(pre_code); + Delete(post_code); Delete(construct_tm); Delete(attributes); Delete(overloaded_name); @@ -2270,6 +2384,8 @@ String *overloaded_name = getOverloadedName(n); String *func_name = NULL; bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); if (l) { if (SwigType_type(Getattr(l, "type")) == T_VOID) { @@ -2306,7 +2422,7 @@ /* Start generating the function */ const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); - methodmods = methodmods ? methodmods : (!is_public(n) ? protected_string : public_string); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); Printf(function_code, " %s static %s %s(", methodmods, return_type, func_name); Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); @@ -2345,6 +2461,22 @@ addThrows(n, "tmap:javain", p); substituteClassname(pt, tm); Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } Printv(imcall, tm, NIL); } else { Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); @@ -2356,8 +2488,17 @@ gencomma = 2; Printf(function_code, "%s %s", param_type, arg); - if (prematureGarbageCollectionPreventionParameter(pt, p)) - Printf(imcall, ", %s", arg); + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } p = Getattr(p, "tmap:in:next"); Delete(arg); @@ -2370,6 +2511,23 @@ // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in module class) if ((tm = Swig_typemap_lookup_new("javaout", n, "", 0))) { addThrows(n, "tmap:javaout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } if (GetFlag(n, "feature:new")) Replaceall(tm, "$owner", "true"); else @@ -2384,6 +2542,8 @@ Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); Printv(module_class_code, function_code, NIL); + Delete(pre_code); + Delete(post_code); Delete(function_code); Delete(return_type); Delete(imcall); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |