java: Fix optional arguments in calls.
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 19 Jul 2011 13:45:11 +0000 (14:45 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Tue, 19 Jul 2011 14:18:36 +0000 (15:18 +0100)
This also adds tests.

generator/generator_java.ml
java/Makefile.am
java/run-java-tests
java/t/GuestFS080OptArgs.java [new file with mode: 0644]

index 9cd84d8..4d51c53 100644 (file)
@@ -106,7 +106,7 @@ public class GuestFS {
         let doc = replace_str longdesc "C<guestfs_" "C<g." in
         let doc =
           if optargs <> [] then
-            doc ^ "\n\nOptional arguments are supplied in the final Map<String,Object> parameter, which is a hash of the argument name to its value (cast to Object).  Pass an empty Map for no optional arguments."
+            doc ^ "\n\nOptional arguments are supplied in the final Map<String,Object> parameter, which is a hash of the argument name to its value (cast to Object).  Pass an empty Map or null for no optional arguments."
           else doc in
         let doc =
           if List.mem ProtocolLimitWarning flags then
@@ -142,6 +142,32 @@ public class GuestFS {
       pr "    if (g == 0)\n";
       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
         name;
+      if optargs <> [] then (
+        pr "\n";
+        pr "    /* Unpack optional args. */\n";
+        pr "    Object _optobj;\n";
+        pr "    long _optargs_bitmask = 0;\n";
+        iteri (
+          fun i argt ->
+            let t, boxed_t, convert, n, default =
+              match argt with
+              | Bool n -> "boolean", "Boolean", ".booleanValue()", n, "false"
+              | Int n -> "int", "Integer", ".intValue()", n, "0"
+              | Int64 n -> "long", "Long", ".longValue()", n, "0"
+              | String n -> "String", "String", "", n, "\"\""
+              | _ -> assert false in
+            pr "    %s %s = %s;\n" t n default;
+            pr "    _optobj = null;\n";
+            pr "    if (optargs != null)\n";
+            pr "      _optobj = optargs.get (\"%s\");\n" n;
+            pr "    if (_optobj != null) {\n";
+            pr "      %s = ((%s) _optobj)%s;\n" n boxed_t convert;
+            pr "      _optargs_bitmask |= %Ld;\n"
+              (Int64.shift_left Int64.one i);
+            pr "    }\n";
+        ) optargs
+      );
+      pr "\n";
       (match ret with
        | RErr ->
            pr "    _%s " name;
@@ -162,6 +188,7 @@ public class GuestFS {
            pr ";\n"
       );
       pr "  }\n";
+      pr "\n";
       pr "  ";
       generate_java_prototype ~privat:true ~native:true name style;
       pr "\n";
@@ -174,7 +201,10 @@ public class GuestFS {
 and generate_java_call_args ~handle (_, args, optargs) =
   pr "(%s" handle;
   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
-  if optargs <> [] then pr ", optargs";
+  if optargs <> [] then (
+    pr ", _optargs_bitmask";
+    List.iter (fun arg -> pr ", %s" (name_of_argt arg)) optargs
+  );
   pr ")"
 
 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
@@ -243,7 +273,21 @@ and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
   if optargs <> [] then (
     if !needs_comma then pr ", ";
     needs_comma := true;
-    pr "HashMap optargs"
+
+    if not native then
+      pr "Map<String, Object> optargs"
+    else (
+      pr "long _optargs_bitmask";
+      List.iter (
+        fun argt ->
+          match argt with
+          | Bool n -> pr ", boolean %s" n
+          | Int n -> pr ", int %s" n
+          | Int64 n -> pr ", long %s" n
+          | String n -> pr ", String %s" n
+          | _ -> assert false
+      ) optargs
+    )
   );
 
   pr ")\n";
@@ -369,8 +413,17 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
         | Int64 n | Pointer (_, n) ->
             pr ", jlong j%s" n
       ) args;
-      if optargs <> [] then
-        pr ", jobject joptargs";
+      if optargs <> [] then (
+        pr ", jlong joptargs_bitmask";
+        List.iter (
+          function
+          | Bool n -> pr ", jboolean j%s" n
+          | Int n -> pr ", jint j%s" n
+          | Int64 n -> pr ", jlong j%s" n
+          | String n -> pr ", jstring j%s" n
+          | _ -> assert false
+        ) optargs
+      );
       pr ")\n";
       pr "{\n";
       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
@@ -484,10 +537,20 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
       ) args;
 
       if optargs <> [] then (
-        (* XXX *)
-        pr "  throw_exception (env, \"%s: internal error: please let us know how to read a Java HashMap parameter from JNI bindings!\");\n" name;
-        pr "  return NULL;\n";
-        pr "  /*\n";
+        pr "  struct guestfs_%s_argv optargs_s;\n" name;
+        pr "  const struct guestfs_%s_argv *optargs = &optargs_s;\n" name;
+        pr "  optargs_s.bitmask = joptargs_bitmask;\n";
+        List.iter (
+          function
+          | Bool n
+          | Int n
+          | Int64 n ->
+              pr "  optargs_s.%s = j%s;\n" n n
+          | String n ->
+              pr "  optargs_s.%s = (*env)->GetStringUTFChars (env, j%s, NULL);\n"
+                n n
+          | _ -> assert false
+        ) optargs;
       );
 
       (* Make the call. *)
@@ -526,6 +589,16 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
         | Pointer _ -> ()
       ) args;
 
+      List.iter (
+        function
+        | Bool n
+        | Int n
+        | Int64 n -> ()
+        | String n ->
+            pr "  (*env)->ReleaseStringUTFChars (env, j%s, optargs_s.%s);\n" n n
+        | _ -> assert false
+      ) optargs;
+
       (* Check for errors. *)
       (match errcode_of_ret ret with
        | `CannotReturnError -> ()
@@ -593,9 +666,6 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
            pr "  return jr;\n"
       );
 
-      if optargs <> [] then
-        pr "  */\n";
-
       pr "}\n";
       pr "\n"
   ) all_functions
index 3ae1123..fe55ec2 100644 (file)
@@ -40,7 +40,8 @@ java_sources = \
 java_tests = \
        Bindtests.java \
        t/GuestFS005Load.java \
-       t/GuestFS010Basic.java
+       t/GuestFS010Basic.java \
+       t/GuestFS080OptArgs.java
 
 EXTRA_DIST = \
        $(java_sources) \
index 64ce079..a9fe957 100755 (executable)
@@ -18,7 +18,7 @@
 
 set -e
 
-for f in t/*.class; do
+for f in $(ls -1 t/*.class | fgrep -v \$); do
   classname=$(basename $f .class)
   $JAVA -Djava.library.path=.libs -ea $classname
 done
\ No newline at end of file
diff --git a/java/t/GuestFS080OptArgs.java b/java/t/GuestFS080OptArgs.java
new file mode 100644 (file)
index 0000000..291a8c3
--- /dev/null
@@ -0,0 +1,63 @@
+/* libguestfs Java bindings
+ * Copyright (C) 2011 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+import java.io.*;
+import java.util.HashMap;
+import com.redhat.et.libguestfs.*;
+
+public class GuestFS080OptArgs
+{
+    public static void main (String[] argv)
+    {
+        try {
+            GuestFS g = new GuestFS ();
+
+            g.add_drive_opts ("/dev/null", null);
+
+            HashMap<String,Object> optargs;
+
+            optargs = new HashMap<String,Object>() {
+                {
+                    put ("readonly", Boolean.TRUE);
+                }
+            };
+            g.add_drive_opts ("/dev/null", optargs);
+
+            optargs = new HashMap<String,Object>() {
+                {
+                    put ("readonly", Boolean.TRUE);
+                    put ("format", "raw");
+                }
+            };
+            g.add_drive_opts ("/dev/null", optargs);
+
+            optargs = new HashMap<String,Object>() {
+                {
+                    put ("readonly", Boolean.TRUE);
+                    put ("format", "raw");
+                    put ("iface", "virtio");
+                }
+            };
+            g.add_drive_opts ("/dev/null", optargs);
+        }
+        catch (Exception exn) {
+            System.err.println (exn);
+            System.exit (1);
+        }
+    }
+}