// Copyright (c) Corporation for National Research Initiatives package org.python.core; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.lang.reflect.InvocationTargetException; import java.lang.InstantiationException; public class PyReflectedConstructor extends PyReflectedFunction { public PyReflectedConstructor(String name) { super(name); } public PyReflectedConstructor(Constructor<?> c) { this(c.getDeclaringClass().getName()); addConstructor(c); } private ReflectedArgs makeArgs(Constructor<?> m) { return new ReflectedArgs(m, m.getParameterTypes(), m.getDeclaringClass(), true); } public void addConstructor(Constructor<?> m) { int mods = m.getModifiers(); // Only add public methods unless we're overriding if (!Modifier.isPublic(mods) && Options.respectJavaAccessibility) { return; } addArgs(makeArgs(m)); } // xxx temporary solution, type ctr will go through __new__ ... PyObject make(PyObject[] args, String[] keywords) { ReflectedCallData callData = new ReflectedCallData(); Object method = null; boolean consumes_keywords = false; PyObject[] allArgs = null; // Check for a matching constructor to call if (nargs > 0) { // PyArgsKeywordsCall signature, if present, is the first if (argslist[0].matches(null, args, keywords, callData)) { method = argslist[0].data; consumes_keywords = argslist[0].flags == ReflectedArgs.PyArgsKeywordsCall; } else { allArgs = args; int i = 1; if (keywords.length > 0) { args = new PyObject[allArgs.length - keywords.length]; System.arraycopy(allArgs, 0, args, 0, args.length); i = 0; } for (; i < nargs; i++) { if (argslist[i].matches(null, args, Py.NoKeywords, callData)) { method = argslist[i].data; break; } } } } // Throw an error if no valid set of arguments if (method == null) { throwError(callData.errArg, args.length, true /* xxx? */, false); } // Do the actual constructor call PyObject obj; try { obj = (PyObject)((Constructor<?>)method).newInstance(callData.getArgsArray()); } catch (Throwable t) { throw Py.JavaError(t); } if (!consumes_keywords) { int offset = args.length; for (int i = 0; i < keywords.length; i++) { obj.__setattr__(keywords[i], allArgs[i + offset]); } } return obj; } @Override public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { if (self == null) { throw Py.TypeError("invalid self argument to constructor"); } Class<?> javaClass = self.getType().getProxyType(); if (javaClass == null) { throw Py.TypeError("self invalid - must be a Java subclass [self=" + self + "]"); } Class<?> declaringClass = argslist[0] == null ? null : argslist[0].declaringClass; // If the declaring class is a pure Java type but we're instantiating a Python proxy, // grab the proxy version of the constructor to instantiate the proper type if ((declaringClass == null || !PyProxy.class.isAssignableFrom(declaringClass)) && !(self.getType() instanceof PyJavaType)) { return PyType.fromClass(javaClass).lookup("__init__").__call__(self, args, keywords); } if (nargs == 0) { throw Py.TypeError("No visible constructors for class (" + javaClass.getName() + ")"); } if (!declaringClass.isAssignableFrom(javaClass)) { throw Py.TypeError("self invalid - must implement: " + declaringClass.getName()); } int mods = declaringClass.getModifiers(); if (Modifier.isInterface(mods)) { throw Py.TypeError("can't instantiate interface (" + declaringClass.getName() + ")"); } else if (Modifier.isAbstract(mods)) { throw Py.TypeError("can't instantiate abstract class (" + declaringClass.getName() + ")"); } if (self.javaProxy != null) { Class<?> sup = javaClass; if (PyProxy.class.isAssignableFrom(sup)) { sup = sup.getSuperclass(); } throw Py.TypeError("instance already instantiated for " + sup.getName()); } ReflectedCallData callData = new ReflectedCallData(); Object method = null; // 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) { // 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. 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; } @Override public PyObject __call__(PyObject[] args, String[] keywords) { if (args.length < 1) { throw Py.TypeError("constructor requires self argument"); } PyObject[] newArgs = new PyObject[args.length - 1]; System.arraycopy(args, 1, newArgs, 0, newArgs.length); return __call__(args[0], newArgs, keywords); } protected void constructProxy(PyObject obj, Constructor<?> ctor, Object[] args, Class<?> proxy) { // Do the actual constructor call Object jself = null; ThreadState ts = Py.getThreadState(); try { ts.pushInitializingProxy(obj); try { jself = ctor.newInstance(args); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof InstantiationException) { Class<?> sup = proxy.getSuperclass(); String msg = "Constructor failed for Java superclass"; if (sup != null) { msg += " " + sup.getName(); } throw Py.TypeError(msg); } else throw Py.JavaError(e); } catch (Throwable t) { throw Py.JavaError(t); } } finally { ts.popInitializingProxy(); } obj.javaProxy = jself; } @Override public PyObject _doget(PyObject container, PyObject wherefound) { if (container == null) { return this; } return new PyMethod(this, container, wherefound); } @Override public String toString() { // printArgs(); return "<java constructor " + __name__ + " " + Py.idstr(this) + ">"; } }