org.python.core.PyJavaClass Maven / Gradle / Ivy
Go to download
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
// Copyright (c) Corporation for National Research Initiatives
package org.python.core;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* A wrapper around a java class.
*/
public class PyJavaClass extends PyClass
{
public PyReflectedConstructor __init__;
public PackageManager __mgr__;
private static InternalTables tbl;
public synchronized final static InternalTables getInternalTables() {
if(tbl == null)
tbl = InternalTables.createInternalTables();
return tbl;
}
public final boolean isLazy() {
return proxyClass == null;
}
public static final PyJavaClass lookup(String name,PackageManager mgr) {
if (tbl.queryCanonical(name)) {
Class c = mgr.findClass(null,name,"forced java class");
check_lazy_allowed(c); // xxx
return lookup(c);
}
PyJavaClass ret = new PyJavaClass(name, mgr);
tbl.putLazyCanonical(name, ret);
return ret;
}
public synchronized static final PyJavaClass lookup(Class c) {
if (tbl == null) {
tbl = InternalTables.createInternalTables();
PyJavaClass jc = new PyJavaClass(true);
jc.init(PyJavaClass.class);
tbl.putCanonical(PyJavaClass.class,jc);
}
PyJavaClass ret = tbl.getCanonical(c);
if (ret != null)
return ret;
PyJavaClass lazy = tbl.getLazyCanonical(c.getName());
if (lazy != null) {
initLazy(lazy);
if (lazy.proxyClass == c) return lazy;
}
Class parent = c.getDeclaringClass();
if (parent == null)
ret = new PyJavaClass(c);
else
ret = new PyJavaInnerClass(c, lookup(parent));
tbl.putCanonical(c,ret);
return ret;
}
private PyJavaClass(boolean fakeArg) {
super(true);
}
protected PyJavaClass(Class c) {
init(c);
}
protected PyJavaClass(String name,PackageManager mgr) {
__name__ = name;
this.__mgr__ = mgr;
}
protected void findModule(PyObject dict) {}
protected Class getProxyClass() {
initialize();
return proxyClass;
}
// for the moment trying to lazily load a PyObject subclass
// is not allowed, (because of the PyJavaClass vs PyType class mismatch)
// pending PyJavaClass becoming likely a subclass of PyType
private static final void check_lazy_allowed(Class c) {
if (PyObject.class.isAssignableFrom(c)) { // xxx
throw Py.TypeError("cannot lazy load PyObject subclass");
}
}
private static final void initLazy(PyJavaClass jc) {
Class c = jc.__mgr__.findClass(null,jc.__name__,"lazy java class");
check_lazy_allowed(c); // xxx
jc.init(c);
tbl.putCanonical(jc.proxyClass,jc);
jc.__mgr__ = null;
}
private boolean initialized=false;
// Prevent recursive calls to initialize()
private boolean initializing=false;
private synchronized void initialize() {
if (initialized || initializing)
return;
initializing = true;
synchronized(PyJavaClass.class) {
if (proxyClass == null) {
initLazy(this);
}
}
init__bases__(proxyClass);
init__dict__();
if (ClassDictInit.class.isAssignableFrom(proxyClass)
&& proxyClass != ClassDictInit.class) {
try {
Method m = proxyClass.getMethod("classDictInit",
new Class[] { PyObject.class });
m.invoke(null, new Object[] { __dict__ });
}
catch (Exception exc) {
// System.err.println("Got exception: " + exc + " " +
// proxyClass);
throw Py.JavaError(exc);
}
}
if (InitModule.class.isAssignableFrom(proxyClass)) {
try {
InitModule m = (InitModule)proxyClass.newInstance();
m.initModule(__dict__);
}
catch (Exception exc) {
// System.err.println("Got exception: " + exc);
throw Py.JavaError(exc);
}
}
initialized = true;
initializing = false;
}
private synchronized void init__dict__() {
if (__dict__ != null)
return;
PyStringMap d = new PyStringMap();
// d.__setitem__("__module__", Py.None);
__dict__ = d;
try {
Method[] methods = getAccessibleMethods(proxyClass);
setBeanInfoCustom(proxyClass, methods);
setFields(proxyClass);
setMethods(proxyClass, methods);
} catch(SecurityException se) {}
}
private synchronized void init__class__(Class c) {
/* xxx disable opt, will need similar opt for types
if (!PyObject.class.isAssignableFrom(c))
return;
try {
Field field = c.getField("__class__");
if (Modifier.isStatic(field.getModifiers()) &&
field.getType().isAssignableFrom(PyJavaClass.class) &&
field.getDeclaringClass() == c)
{
field.set(null, this);
}
}
catch (NoSuchFieldException exc) {}
catch (IllegalAccessException exc1) {} */
}
private synchronized void init__bases__(Class c) {
if (__bases__ != null) return;
Class interfaces[] = getAccessibleInterfaces(c);
int nInterfaces = interfaces.length;
int nBases = 0;
int i;
for (i=0; i 7)
continue;
PyObject prop = lookup(name, false);
if (prop != null && prop instanceof PyBeanProperty) {
PyBeanProperty beanProp = ((PyBeanProperty)prop).copy();
beanProp.field = field;
__dict__.__setitem__(name, beanProp);
continue;
}
}
__dict__.__setitem__(name, new PyReflectedField(field));
}
}
/* Produce a good Python name for a Java method. If the Java method
ends in '$', strip it (this handles reserved Java keywords) Don't
make any changes to keywords since this is now handled by parser
*/
private String getName(String name) {
if (name.endsWith("$")) name = name.substring(0, name.length()-1);
return name.intern();
}
private void addMethod(Method meth) {
String name = getName(meth.getName());
if (name == "_getPyInstance" || name == "_setPyInstance" ||
name == "_getPySystemState" || name == "_setPySystemState")
{
return;
}
// Special case to handle a few troublesome methods in java.awt.*.
// These methods are all deprecated and interfere too badly with
// bean properties to be tolerated. This is totally a hack, but a
// lot of code that uses java.awt will break without it.
String classname = proxyClass.getName();
if (classname.startsWith("java.awt.") &&
classname.indexOf('.', 9) == -1)
{
if (name == "layout" || name == "insets" ||
name == "size" || name == "minimumSize" ||
name == "preferredSize" || name == "maximumSize" ||
name == "bounds" || name == "enable")
{
return;
}
}
// See if any of my superclasses are using 'name' for something
// else. Or if I'm already using it myself
PyObject o = lookup(name, false);
// If it's being used as a function, then things get more
// interesting...
PyReflectedFunction func;
if (o != null && o instanceof PyReflectedFunction) {
func = (PyReflectedFunction)o;
PyObject o1 = __dict__.__finditem__(name);
/* If this function already exists, add this method to the
signature. If this alters the signature of the function in
some significant way, then return a duplicate and stick it in
the __dict__ */
if (o1 != o) {
if (func.handles(meth)){
return;
}
func = func.copy();
}
func.addMethod(meth);
} else {
func = new PyReflectedFunction(meth);
try {
Field docField = proxyClass.getField("__doc__" + name);
int mods = docField.getModifiers();
if (docField.getType() == PyString.class &&
Modifier.isPublic(mods) &&
Modifier.isStatic(mods));
func.__doc__ = (PyString) docField.get(null);
} catch (NoSuchFieldException ex) {
} catch (SecurityException ex) {
} catch (IllegalAccessException ex) {}
}
__dict__.__setitem__(name, func);
}
/**
* Return the list of all accessible methods for a class. This will
* only the public methods unless Options.respectJavaAccessibility is
* false, in which case all methods are returned.
*/
private static Method[] getAccessibleMethods(Class c) {
if (!JavaAccessibility.accessIsMutable())
// returns just the public methods
return c.getMethods();
Method[] declared = c.getDeclaredMethods();
for (int i=0; i < declared.length; i++) {
// TBD: this is a permanent change. Should we provide a way to
// restore the original accessibility flag?
JavaAccessibility.setAccessible(declared[i], true);
}
return declared;
}
private boolean ignoreMethod(Method method) {
Class[] exceptions = method.getExceptionTypes();
for (int j = 0; j < exceptions.length; j++) {
if (exceptions[j] == PyIgnoreMethodTag.class) {
return true;
}
}
return false;
}
/* Add all methods declared by this class */
private void setMethods(Class c, Method[] methods) {
for (int i=0; i 1 && Character.isUpperCase(s.charAt(1)))
return s;
char[] cs = s.toCharArray();
cs[0] = Character.toLowerCase(c0);
return new String(cs);
} else {
return s;
}
}
// This method is a workaround for Netscape's stupid security bug!
private void setBeanInfoCustom(Class c, Method[] meths) {
//try {
int i;
int n = meths.length;
for (i=0; i 0)
eClass.getInterfaces()[0].getClassLoader();
// And of Mac workaround
if (!(java.util.EventListener.class.isAssignableFrom(eClass)))
continue;
String name = eClass.getName();
int idot = name.lastIndexOf('.');
if (idot != -1)
name = decapitalize(name.substring(idot+1));
addEvent(name, eClass, method, eClass.getMethods());
}
/*} catch (Throwable t) {
System.err.println("Custom Bean error: "+t);
t.printStackTrace();
}*/
}
/**
* Return the list of all accessible constructors for a class. This
* will only the public constructors unless
* Options.respectJavaAccessibility is false, in which case all
* constructors are returned. Note that constructors are not
* inherited like methods or fields.
*/
private static Constructor[] getAccessibleConstructors(Class c) {
if (!JavaAccessibility.accessIsMutable())
// returns just the public fields
return c.getConstructors();
// return all constructors
Constructor[] declared = c.getDeclaredConstructors();
for (int i=0; i < declared.length; i++) {
// TBD: this is a permanent change. Should we provide a way to
// restore the original accessibility flag?
JavaAccessibility.setAccessible(declared[i], true);
}
return declared;
}
private boolean ignoreConstructor(Constructor method) {
Class[] exceptions = method.getExceptionTypes();
for (int j = 0; j < exceptions.length; j++) {
if (exceptions[j] == PyIgnoreMethodTag.class) {
return true;
}
}
return false;
}
private void setConstructors(Class c) {
if (Modifier.isInterface(c.getModifiers())) {
__init__ = null;
} else {
Constructor[] constructors = getAccessibleConstructors(c);
for (int i = 0; i < constructors.length; i++) {
if (ignoreConstructor(constructors[i])) {
continue;
}
if (__init__ == null) {
__init__ = new PyReflectedConstructor(constructors[i]);
} else {
__init__.addConstructor(constructors[i]);
}
}
if (__init__ != null) {
__dict__.__setitem__("__init__", __init__);
}
}
}
private boolean constructorsInitialized=false;
synchronized void initConstructors() {
if (constructorsInitialized)
return;
initialize();
setConstructors(proxyClass);
constructorsInitialized = true;
}
/*
If the new name conflicts with a Python keyword, add an '_'
*/
private static java.util.Hashtable keywords=null;
private static String unmangleKeyword(String name) {
if (keywords == null) {
keywords = new java.util.Hashtable();
String[] words = new String[]
{"or", "and", "not", "is", "in", "lambda", "if", "else", "elif",
"while", "for", "try", "except", "def", "class", "finally",
"print",
"pass", "break", "continue", "return", "import", "from", "del",
"raise", "global", "exec", "assert"};
for (int i=0; i";
}
}