SF.net SVN: jython:[7113] trunk/jython

[email protected] Wed, 08 Sep 2010 07:18:49 +0000
Newsgroups gmane.comp.lang.jython.cvs
Message-ID <[email protected]>
Revision: 7113
          http://jython.svn.sourceforge.net/jython/?rev=7113&view=rev
Author:   zyasoft
Date:     2010-09-08 07:18:48 +0000 (Wed, 08 Sep 2010)

Log Message:
-----------
Fixed #1503, Java constructors should take keyword arguments.
Thanks Geoffrey French!

Modified Paths:
--------------
    trunk/jython/NEWS
    trunk/jython/src/org/python/core/PyReflectedConstructor.java

Modified: trunk/jython/NEWS
===================================================================
--- trunk/jython/NEWS	2010-09-08 06:27:14 UTC (rev 7112)
+++ trunk/jython/NEWS	2010-09-08 07:18:48 UTC (rev 7113)
@@ -2,6 +2,7 @@
 
 Jython 2.5.2b2
   Bugs Fixed
+    - [ 1503 ] Java constructors should take keyword arguments
     - [ 1648 ] Incomplete implementation of pep328 for relative imports
     - [ 1611 ] Jython bytecode violated JLS, causing NPE on Sun's JVM when using -Xcomp option
     - [ 1643 ] Tools subdirectory still exists in trunk

Modified: trunk/jython/src/org/python/core/PyReflectedConstructor.java
===================================================================
--- trunk/jython/src/org/python/core/PyReflectedConstructor.java	2010-09-08 06:27:14 UTC (rev 7112)
+++ trunk/jython/src/org/python/core/PyReflectedConstructor.java	2010-09-08 07:18:48 UTC (rev 7113)
@@ -115,32 +115,77 @@
         }
         ReflectedCallData callData = new ReflectedCallData();
         Object method = null;
-        // Remove keyword args
+        
+        // If we have keyword args, there are two ways this can be handled;
+        // a) we find a constructor that takes keyword args, and use it.
+        // b) we don't, in which case we strip the keyword args, and pass the
+        //     non-keyword args, and then use the keyword args to set bean properties
+        // If we don't have keyword args; just look for a constructor that
+        // takes the right number of args.
         int nkeywords = keywords.length;
+        ReflectedArgs rargs = null;
         PyObject[] allArgs = args;
+        boolean usingKeywordArgsCtor = false;
         if (nkeywords > 0) {
-            args = new PyObject[allArgs.length - nkeywords];
-            System.arraycopy(allArgs, 0, args, 0, args.length);
-        }
-        // Check for a matching constructor to call
-        int n = nargs;
-        for (int i = 0; i < n; i++) {
-            ReflectedArgs rargs = argslist[i];
-            if (rargs.matches(null, args, Py.NoKeywords, callData)) {
-                method = rargs.data;
-                break;
+            // We have keyword args.
+            
+            // Look for a constructor; the ReflectedArgs#matches() method exits early in the case
+            // where keyword args are used
+            int n = nargs;
+            for (int i = 0; i < n; i++) {
+                rargs = argslist[i];
+                if (rargs.matches(null, args, keywords, callData)) {
+                    method = rargs.data;
+                    break;
+                }
             }
-        }
+            
+            if (method != null) {
+                // Constructor found that will accept the keyword args
+                usingKeywordArgsCtor = true;
+            } else {
+                // No constructor found that will take keyword args
+                
+                // Remove the keyword args  
+                args = new PyObject[allArgs.length - nkeywords];
+                System.arraycopy(allArgs, 0, args, 0, args.length);
+
+                // Look for a constructor with no keyword args
+                for (int i = 0; i < n; i++) {
+                    rargs = argslist[i];
+                    if (rargs.matches(null, args, Py.NoKeywords, callData)) {
+                        method = rargs.data;
+                        break;
+                    }
+                }
+            }
+       } else {
+           // Just look for a constructor with no keyword args
+           int n = nargs;
+           for (int i = 0; i < n; i++) {
+               rargs = argslist[i];
+               if (rargs.matches(null, args, Py.NoKeywords, callData)) {
+                   method = rargs.data;
+                   break;
+               }
+           }
+       }
+        
         // Throw an error if no valid set of arguments
         if (method == null) {
             throwError(callData.errArg, args.length, false, false);
         }
         // Do the actual constructor call
         constructProxy(self, (Constructor<?>)method, callData.getArgsArray(), javaClass);
-        // Do setattr's for keyword args
-        int offset = args.length;
-        for (int i = 0; i < nkeywords; i++) {
-            self.__setattr__(keywords[i], allArgs[i + offset]);
+        // Do setattr's for keyword args. This convenience allows Java bean properties to be set in
+        // by a Python constructor call.
+        // However, this is not done if the Java constructor accepts (PyObject[], String[]) as its arguments,
+        // in which case the intention is that the Java constructor will handle the keyword arguments itself.
+        if (!usingKeywordArgsCtor) {
+            int offset = args.length;
+            for (int i = 0; i < nkeywords; i++) {
+                self.__setattr__(keywords[i], allArgs[i + offset]);
+            }
         }
         return Py.None;
     }


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd