exclusion from guessing for non-annotation member types

support for PyClass
support for name pattern for INIT
minor cleanup
master
Abhinav Sarkar 2009-10-31 00:16:42 +05:30
parent cc159354ce
commit f4c4ef73bb
10 changed files with 946 additions and 909 deletions

View File

@ -3,6 +3,7 @@
<classpathentry kind="src" path="src/main/java"/> <classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/example/java"/> <classpathentry kind="src" path="src/example/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="JYTHON_HOME/jython.jar" sourcepath="/JYTHON_HOME/Doc/javadoc"/> <classpathentry kind="var" path="JYTHON_HOME/jython.jar" sourcepath="/JYTHON_HOME/src"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -5,6 +5,11 @@
<projects> <projects>
</projects> </projects>
<buildSpec> <buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name> <name>org.eclipse.jdt.core.javabuilder</name>
<arguments> <arguments>
@ -13,5 +18,6 @@
</buildSpec> </buildSpec>
<natures> <natures>
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.python.pydev.pythonNature</nature>
</natures> </natures>
</projectDescription> </projectDescription>

View File

@ -6,6 +6,7 @@ import static net.abhinavsarkar.jywrapper.Messages._;
import net.abhinavsarkar.jywrapper.annotation.Wraps; import net.abhinavsarkar.jywrapper.annotation.Wraps;
import net.abhinavsarkar.jywrapper.exception.PythonImportNotFoundException; import net.abhinavsarkar.jywrapper.exception.PythonImportNotFoundException;
import org.python.core.PyClass;
import org.python.core.PyFunction; import org.python.core.PyFunction;
import org.python.core.PyModule; import org.python.core.PyModule;
import org.python.core.PyObject; import org.python.core.PyObject;
@ -50,7 +51,9 @@ public final class JyWrapper {
} }
final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName); final PyObject pyImport = PyImportLoader.loadPyImport(pyImportName);
if (!(pyImport instanceof PyType || pyImport instanceof PyModule)) { if (!(pyImport instanceof PyType
|| pyImport instanceof PyModule
|| pyImport instanceof PyClass)) {
throw new IllegalArgumentException(_("JyWrapper.5", pyImportName)); //$NON-NLS-1$ throw new IllegalArgumentException(_("JyWrapper.5", pyImportName)); //$NON-NLS-1$
} }
return Util.py2Java(pyImport, javaClass); return Util.py2Java(pyImport, javaClass);

View File

@ -7,16 +7,16 @@ import java.util.ResourceBundle;
final class Messages { final class Messages {
private static final String BUNDLE_NAME = "net.abhinavsarkar.jywrapper.messages"; //$NON-NLS-1$ private static final String BUNDLE_NAME = "net.abhinavsarkar.jywrapper.messages"; //$NON-NLS-1$
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle private static final ResourceBundle RESOURCE_BUNDLE =
.getBundle(BUNDLE_NAME); ResourceBundle.getBundle(BUNDLE_NAME);
private Messages() { private Messages() {
} }
public static String getString(String key) { public static String getString(final String key) {
try { try {
return RESOURCE_BUNDLE.getString(key); return RESOURCE_BUNDLE.getString(key);
} catch (MissingResourceException e) { } catch (final MissingResourceException e) {
return '!' + key + '!'; return '!' + key + '!';
} }
} }

View File

@ -3,15 +3,16 @@ package net.abhinavsarkar.jywrapper;
import net.abhinavsarkar.jywrapper.PyObjectProxy.MemberType; import net.abhinavsarkar.jywrapper.PyObjectProxy.MemberType;
public enum PyAttributeType { public enum PyAttributeType {
GETTER(MemberType.GETTER), SETTER(MemberType.SETTER), CONST(MemberType.CONST); GETTER(MemberType.GETTER), SETTER(MemberType.SETTER), CONST(MemberType.CONST);
private final MemberType memberType; private final MemberType memberType;
private PyAttributeType(MemberType memberType) { private PyAttributeType(final MemberType memberType) {
this.memberType = memberType; this.memberType = memberType;
} }
public MemberType getMemberType() { MemberType getMemberType() {
return memberType; return memberType;
} }
} }

View File

@ -31,27 +31,27 @@ public final class PyImportLoader {
* @return * @return
* @throws PythonImportNotFoundException * @throws PythonImportNotFoundException
*/ */
public static PyObject loadPyImport(String fullImportName) public static PyObject loadPyImport(final String fullImportName)
throws PythonImportNotFoundException { throws PythonImportNotFoundException {
if (!loadedPyImports.containsKey(fullImportName)) { if (!loadedPyImports.containsKey(fullImportName)) {
int i = fullImportName.lastIndexOf('.'); final int i = fullImportName.lastIndexOf('.');
String errorMsg = _("PyImportLoader.1", fullImportName); //$NON-NLS-1$ final String errorMsg = _("PyImportLoader.1", fullImportName); //$NON-NLS-1$
PyObject pyImport; PyObject pyImport;
if (i == -1) { if (i == -1) {
String pyModuleName = fullImportName; final String pyModuleName = fullImportName;
try { try {
pyImport = importer.__call__(Py.newString(pyModuleName)); pyImport = importer.__call__(Py.newString(pyModuleName));
} catch (PyException pye) { } catch (final PyException pye) {
throw new PythonImportNotFoundException(errorMsg, pye); throw new PythonImportNotFoundException(errorMsg, pye);
} }
} else { } else {
String pyModuleName = fullImportName.substring(0, i); final String pyModuleName = fullImportName.substring(0, i);
String pyClassName = fullImportName.substring(i + 1); final String pyClassName = fullImportName.substring(i + 1);
try { try {
pyImport = importer.__call__(Py.newString(pyModuleName)) pyImport = importer.__call__(Py.newString(pyModuleName))
.__getattr__(pyClassName); .__getattr__(pyClassName);
} catch (PyException pye) { } catch (final PyException pye) {
throw new PythonImportNotFoundException(errorMsg, pye); throw new PythonImportNotFoundException(errorMsg, pye);
} }
} }

View File

@ -10,11 +10,11 @@ public enum PyMethodType {
private final MemberType memberType; private final MemberType memberType;
private PyMethodType(MemberType memberType) { private PyMethodType(final MemberType memberType) {
this.memberType = memberType; this.memberType = memberType;
} }
public MemberType getMemberType() { MemberType getMemberType() {
return memberType; return memberType;
} }
} }

View File

@ -8,6 +8,7 @@ import static net.abhinavsarkar.jywrapper.Messages._;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.EnumSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import net.abhinavsarkar.jywrapper.annotation.PyAttribute; import net.abhinavsarkar.jywrapper.annotation.PyAttribute;
@ -15,6 +16,7 @@ import net.abhinavsarkar.jywrapper.annotation.PyMethod;
import net.abhinavsarkar.jywrapper.exception.PythonImportInstantiationError; import net.abhinavsarkar.jywrapper.exception.PythonImportInstantiationError;
import org.python.core.Py; import org.python.core.Py;
import org.python.core.PyClass;
import org.python.core.PyException; import org.python.core.PyException;
import org.python.core.PyFunction; import org.python.core.PyFunction;
import org.python.core.PyModule; import org.python.core.PyModule;
@ -27,12 +29,17 @@ final class PyObjectProxy implements InvocationHandler {
private static final String JAVA_COMPARE_METHOD_NAME = "compareTo"; //$NON-NLS-1$ private static final String JAVA_COMPARE_METHOD_NAME = "compareTo"; //$NON-NLS-1$
private static final String INIT_METHOD_NAME = "initialize"; //$NON-NLS-1$
private static final String GETTER_METHOD_PREFIX = "get"; //$NON-NLS-1$ private static final String GETTER_METHOD_PREFIX = "get"; //$NON-NLS-1$
private static final String SETTER_METHOD_PREFIX = "set"; //$NON-NLS-1$ private static final String SETTER_METHOD_PREFIX = "set"; //$NON-NLS-1$
private static final String CONST_METHOD_PREFIX = "const"; //$NON-NLS-1$ private static final String CONST_METHOD_PREFIX = "const"; //$NON-NLS-1$
private static final EnumSet<MemberType> NON_ANNOTATED_MEMBERS =
EnumSet.of(MemberType.COMPARE, MemberType.SPECIAL, MemberType.PYPROXY_INTERFACE);
private static enum JavaSpecialMethod { private static enum JavaSpecialMethod {
equals("__eq__"), hashCode("__hash__"), toString("__str__"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ equals("__eq__"), hashCode("__hash__"), toString("__str__"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@ -81,8 +88,8 @@ final class PyObjectProxy implements InvocationHandler {
public static Object invoke(final PyObject pyObject, final Method method, public static Object invoke(final PyObject pyObject, final Method method,
final Object[] args) throws NoSuchMethodException { final Object[] args) throws NoSuchMethodException {
try { try {
return findAndInvokePyMethod(pyObject, return findAndInvokePyMethod(
method.getReturnType(), pyObject, method.getReturnType(),
NumericMethod.valueOf(method.getName()).pyEquiv, args); NumericMethod.valueOf(method.getName()).pyEquiv, args);
} catch (final IllegalArgumentException ex) { } catch (final IllegalArgumentException ex) {
throw new NoSuchMethodException(); throw new NoSuchMethodException();
@ -101,7 +108,7 @@ final class PyObjectProxy implements InvocationHandler {
}; };
public Object invoke(final PyObject pyObject) { public Object invoke(final PyObject pyObject) {
return Void.TYPE; return null;
} }
} }
@ -113,15 +120,22 @@ final class PyObjectProxy implements InvocationHandler {
throws NoSuchMethodException { throws NoSuchMethodException {
final PyMethod annotation = method.getAnnotation(PyMethod.class); final PyMethod annotation = method.getAnnotation(PyMethod.class);
if (annotation != null if (annotation != null && annotation.type() == PyMethodType.INIT) {
&& annotation.type() == PyMethodType.INIT) {
synchronized (pyObject) { synchronized (pyObject) {
return initialize(pyObject, pyImportName, javaClass, args); return initialize(pyObject, pyImportName, javaClass, args);
} }
} }
final String methodName = method.getName();
if (INIT_METHOD_NAME.equals(methodName)) {
synchronized (pyObject) {
return initialize(pyObject, pyImportName, javaClass, args);
}
}
throw new NoSuchMethodException( throw new NoSuchMethodException(
_("JyWrapper.15", "initialization method", //$NON-NLS-1$ //$NON-NLS-2$ _("JyWrapper.15", "initialization method", //$NON-NLS-1$ //$NON-NLS-2$
method.getName(), pyImportName)); methodName, pyImportName));
} }
}, },
CALL { CALL {
@ -144,17 +158,17 @@ final class PyObjectProxy implements InvocationHandler {
final Method method, final Object[] args, final String pyImportName) final Method method, final Object[] args, final String pyImportName)
throws NoSuchMethodException { throws NoSuchMethodException {
String methodName = method.getName(); String methodName = method.getName();
final PyMethod annotation = method.getAnnotation(PyMethod.class); final PyMethod annotation = method.getAnnotation(PyMethod.class);
if (annotation != null if (annotation != null && annotation.type() == PyMethodType.DIRECT) {
&& annotation.type() == PyMethodType.DIRECT) {
final String name = annotation.method(); final String name = annotation.method();
if (!"".equals(name)) { //$NON-NLS-1$ if (!"".equals(name)) { //$NON-NLS-1$
methodName = name; methodName = name;
} }
} }
try { try {
return findAndInvokePyMethod(pyObject, return findAndInvokePyMethod(
method.getReturnType(), methodName, args); pyObject, method.getReturnType(), methodName, args);
} catch (final NoSuchMethodException e) { } catch (final NoSuchMethodException e) {
throw new NoSuchMethodException( throw new NoSuchMethodException(
_("JyWrapper.15", "direct method", //$NON-NLS-1$ //$NON-NLS-2$ _("JyWrapper.15", "direct method", //$NON-NLS-1$ //$NON-NLS-2$
@ -168,8 +182,8 @@ final class PyObjectProxy implements InvocationHandler {
final Method method, final Object[] args, final String pyImportName) final Method method, final Object[] args, final String pyImportName)
throws NoSuchMethodException { throws NoSuchMethodException {
try { try {
return findAndInvokePyMethod(pyObject, return findAndInvokePyMethod(
method.getReturnType(), pyObject, method.getReturnType(),
Util.camelCase2UnderScore(method.getName()), args); Util.camelCase2UnderScore(method.getName()), args);
} catch (final NoSuchMethodException e) { } catch (final NoSuchMethodException e) {
throw new NoSuchMethodException( throw new NoSuchMethodException(
@ -185,8 +199,8 @@ final class PyObjectProxy implements InvocationHandler {
throws NoSuchMethodException { throws NoSuchMethodException {
for (final RichComparisonOperator compOp : RichComparisonOperator.values()) { for (final RichComparisonOperator compOp : RichComparisonOperator.values()) {
try { try {
if ((Boolean) findAndInvokePyMethod(pyObject, if ((Boolean) findAndInvokePyMethod(
Boolean.class, compOp.name(), args)) { pyObject, Boolean.class, compOp.name(), args)) {
return compOp.returnValue(); return compOp.returnValue();
} }
} catch (final PyException e) { } catch (final PyException e) {
@ -199,7 +213,7 @@ final class PyObjectProxy implements InvocationHandler {
} }
try { try {
return (Integer) findAndInvokePyMethod( return findAndInvokePyMethod(
pyObject, Integer.class, "__cmp__", args); //$NON-NLS-1$ pyObject, Integer.class, "__cmp__", args); //$NON-NLS-1$
} catch (final PyException e) { } catch (final PyException e) {
if (!e.type.equals(Py.NotImplementedError)) { if (!e.type.equals(Py.NotImplementedError)) {
@ -240,8 +254,7 @@ final class PyObjectProxy implements InvocationHandler {
PyObject attrValue = null; PyObject attrValue = null;
String attrName = methodName; String attrName = methodName;
if (annotation != null if (annotation != null && annotation.type() == PyAttributeType.GETTER) {
&& annotation.type() == PyAttributeType.GETTER) {
attrName = annotation.attribute(); attrName = annotation.attribute();
if (!"".equals(attrName)) { //$NON-NLS-1$ if (!"".equals(attrName)) { //$NON-NLS-1$
synchronized (pyObject) { synchronized (pyObject) {
@ -279,8 +292,7 @@ final class PyObjectProxy implements InvocationHandler {
final PyAttribute annotation = method.getAnnotation(PyAttribute.class); final PyAttribute annotation = method.getAnnotation(PyAttribute.class);
String attrName = null; String attrName = null;
if (annotation != null if (annotation != null && annotation.type() == PyAttributeType.SETTER) {
&& annotation.type() == PyAttributeType.SETTER) {
attrName = annotation.attribute(); attrName = annotation.attribute();
if ("".equals(attrName)) { //$NON-NLS-1$ if ("".equals(attrName)) { //$NON-NLS-1$
attrName = null; attrName = null;
@ -290,8 +302,8 @@ final class PyObjectProxy implements InvocationHandler {
if (attrName == null if (attrName == null
&& methodName.startsWith(SETTER_METHOD_PREFIX) && methodName.startsWith(SETTER_METHOD_PREFIX)
&& args.length == 1) { && args.length == 1) {
attrName = Util.camelCase2UnderScore(methodName).substring( attrName = Util.camelCase2UnderScore(methodName)
SETTER_METHOD_PREFIX.length() + 1); .substring(SETTER_METHOD_PREFIX.length() + 1);
} }
if (attrName != null) { if (attrName != null) {
@ -313,8 +325,7 @@ final class PyObjectProxy implements InvocationHandler {
return Void.TYPE; return Void.TYPE;
} catch (final PyException e) { } catch (final PyException e) {
if (e.type.equals(Py.AttributeError) if (e.type.equals(Py.AttributeError)
&& e.value.toString().equals( && e.value.toString().equals( "can't set attribute")) { //$NON-NLS-1$
"can't set attribute")) { //$NON-NLS-1$
throw new IllegalAccessException( throw new IllegalAccessException(
_("JyWrapper.13", attrName)); //$NON-NLS-1$ _("JyWrapper.13", attrName)); //$NON-NLS-1$
} }
@ -459,9 +470,9 @@ final class PyObjectProxy implements InvocationHandler {
final String methodName = method.getName(); final String methodName = method.getName();
if (!METHOD_JUMP_TABLE.containsKey(method)) { if (!METHOD_JUMP_TABLE.containsKey(method)) {
//check if the method is "compareTo"
if (Comparable.class.isAssignableFrom(javaClass) if (Comparable.class.isAssignableFrom(javaClass)
&& JAVA_COMPARE_METHOD_NAME.equals(methodName)) { && JAVA_COMPARE_METHOD_NAME.equals(methodName)) {
//check if the method is "compareTo"
METHOD_JUMP_TABLE.putIfAbsent(method, MemberType.COMPARE); METHOD_JUMP_TABLE.putIfAbsent(method, MemberType.COMPARE);
} else { } else {
//check if the method is one of the special methods //check if the method is one of the special methods
@ -492,6 +503,10 @@ final class PyObjectProxy implements InvocationHandler {
// try each method types one by one to guess the correct one // try each method types one by one to guess the correct one
for (final MemberType methodType : MemberType.values()) { for (final MemberType methodType : MemberType.values()) {
if (NON_ANNOTATED_MEMBERS.contains(methodType)) {
continue;
}
try { try {
final Object retVal = methodType.invoke( final Object retVal = methodType.invoke(
pyObject, javaClass, method, args, pyImportName); pyObject, javaClass, method, args, pyImportName);
@ -527,7 +542,7 @@ final class PyObjectProxy implements InvocationHandler {
if (pyImport instanceof PyModule) { if (pyImport instanceof PyModule) {
throw new PythonImportInstantiationError(_("JyWrapper.4", pyImportName)); //$NON-NLS-1$ throw new PythonImportInstantiationError(_("JyWrapper.4", pyImportName)); //$NON-NLS-1$
} }
if (!(pyImport instanceof PyType)) { if (!(pyImport instanceof PyType || pyImport instanceof PyClass)) {
throw new PythonImportInstantiationError(_("JyWrapper.9")); //$NON-NLS-1$ throw new PythonImportInstantiationError(_("JyWrapper.9")); //$NON-NLS-1$
} }

View File

@ -3,6 +3,7 @@ package net.abhinavsarkar.jywrapper;
import static net.abhinavsarkar.jywrapper.Messages._; import static net.abhinavsarkar.jywrapper.Messages._;
import org.python.core.Py; import org.python.core.Py;
import org.python.core.PyClass;
import org.python.core.PyFunction; import org.python.core.PyFunction;
import org.python.core.PyModule; import org.python.core.PyModule;
import org.python.core.PyObject; import org.python.core.PyObject;
@ -56,12 +57,22 @@ final class Util {
pyType.getName()); pyType.getName());
} }
return pyType.getName(); return pyType.getName();
} else if (pyObject instanceof PyClass) {
final PyClass pyClass = (PyClass) pyObject;
final PyObject mod = pyClass.__dict__.__finditem__("__module__");
String smod;
if (mod == null || !(mod instanceof PyString)) {
smod = "<unknown>";
} else {
smod = ((PyString) mod).toString();
}
return smod + "." + pyClass.__name__;
} else if (pyObject instanceof PyModule) { } else if (pyObject instanceof PyModule) {
return ((PyModule) pyObject).toString(); return ((PyModule) pyObject).toString();
} else if (pyObject instanceof PyFunction) { } else if (pyObject instanceof PyFunction) {
final PyFunction pyFunction = (PyFunction) pyObject; final PyFunction pyFunction = (PyFunction) pyObject;
return String.format("%s.%s", pyFunction.__module__, //$NON-NLS-1$ return String.format(
pyFunction.__name__); "%s.%s", pyFunction.__module__, pyFunction.__name__); //$NON-NLS-1$
} else { } else {
return getPyImportName(pyObject.getType()); return getPyImportName(pyObject.getType());
} }

View File

@ -3,11 +3,11 @@ JyWrapper.1=Cannot convert Python object: {0} to a Java object of class {1}
JyWrapper.2=Cannot convert Python Type {0} to Java Class {1} JyWrapper.2=Cannot convert Python Type {0} to Java Class {1}
JyWrapper.3=Cannot not instantiate the Python type: {0} JyWrapper.3=Cannot not instantiate the Python type: {0}
JyWrapper.4=Python module {0} can be instantiated statically only JyWrapper.4=Python module {0} can be instantiated statically only
JyWrapper.5={0} is not a Python Type or Module JyWrapper.5={0} is not a Python Type, Class or Module
JyWrapper.6=parameter "{0}" is null JyWrapper.6=parameter "{0}" is null
JyWrapper.7=No Python import name annotated on the Java Class {0} JyWrapper.7=No Python import name annotated on the Java Class {0}
JyWrapper.8={0} is not an Interface JyWrapper.8={0} is not an Interface
JyWrapper.9=Cannot instantiate a Python non type JyWrapper.9=Cannot instantiate a non Python Type or Class
JyWrapper.10=Instance method "{0}" called on a Python Type JyWrapper.10=Instance method "{0}" called on a Python Type
JyWrapper.11=No comparison methods found in the backing Python object JyWrapper.11=No comparison methods found in the backing Python object
JyWrapper.12=Trying to get instance attribute "{0}" from a Python Type JyWrapper.12=Trying to get instance attribute "{0}" from a Python Type