From: <cg...@us...> - 2009-07-12 05:41:47
|
Revision: 6532 http://jython.svn.sourceforge.net/jython/?rev=6532&view=rev Author: cgroves Date: 2009-07-12 05:41:43 +0000 (Sun, 12 Jul 2009) Log Message: ----------- Set the name of the produced proxy class to the value from __javaclass__ if it's set in the Python class. Modified Paths: -------------- trunk/jython/Lib/test/test_java_subclasses.py trunk/jython/NEWS trunk/jython/src/org/python/compiler/Module.java trunk/jython/src/org/python/core/MakeProxies.java trunk/jython/src/org/python/core/PyType.java trunk/jython/src/org/python/core/util/StringUtil.java Modified: trunk/jython/Lib/test/test_java_subclasses.py =================================================================== --- trunk/jython/Lib/test/test_java_subclasses.py 2009-07-12 00:53:25 UTC (rev 6531) +++ trunk/jython/Lib/test/test_java_subclasses.py 2009-07-12 05:41:43 UTC (rev 6532) @@ -321,10 +321,35 @@ self.assertEquals(len(called), 1) +class SettingJavaClassNameTest(unittest.TestCase): + def test_setting_name(self): + class Fixedname(Runnable): + __javaname__ = 'name.set.in.Python' + def run(self): + pass + self.assertEquals('name.set.in.Python', Fixedname().getClass().name) + try: + class NumberPackageName(Runnable): + __javaname__ = 'ok.7.ok' + def run(self): + pass + self.fail("Shouldn't be able to set a package name that starts with a digit") + except TypeError: + pass + try: + class LiteralPackageName(Runnable): + __javaname__ = 'ok.true.ok' + def run(self): + pass + self.fail("Shouldn't be able to use a Java literal as a package name") + except TypeError: + pass + def test_main(): test_support.run_unittest(InterfaceTest, TableModelTest, AutoSuperTest, PythonSubclassesTest, AbstractOnSyspathTest, - ContextClassloaderTest) + ContextClassloaderTest, + SettingJavaClassNameTest) Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2009-07-12 00:53:25 UTC (rev 6531) +++ trunk/jython/NEWS 2009-07-12 05:41:43 UTC (rev 6532) @@ -4,6 +4,8 @@ New Features - Upgraded to ANTLR 3.1.3 - [ 1859477 ] Dynamically loaded ServletFilters like PyServlet + - Setting __javaname__ in classes subclassing Java classes or implementing Java interfaces sets + the name of the produced proxy class. Bugs Fixed - [ 1366 ] parsing of lamda expression fails - [ 1365 ] continuation lines fail in interactive interpreter Modified: trunk/jython/src/org/python/compiler/Module.java =================================================================== --- trunk/jython/src/org/python/compiler/Module.java 2009-07-12 00:53:25 UTC (rev 6531) +++ trunk/jython/src/org/python/compiler/Module.java 2009-07-12 05:41:43 UTC (rev 6532) @@ -12,6 +12,11 @@ import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.python.antlr.ParseException; +import org.python.antlr.PythonTree; +import org.python.antlr.ast.Suite; +import org.python.antlr.base.mod; import org.python.core.CodeBootstrap; import org.python.core.CodeFlag; import org.python.core.CodeLoader; @@ -19,11 +24,7 @@ import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyRunnableBootstrap; -import org.objectweb.asm.Type; -import org.python.antlr.ParseException; -import org.python.antlr.PythonTree; -import org.python.antlr.ast.Suite; -import org.python.antlr.base.mod; +import org.python.core.util.StringUtil; class PyIntegerConstant extends Constant implements ClassConstants, Opcodes { @@ -365,20 +366,7 @@ } List codes; - private boolean isJavaIdentifier(String s) { - char[] chars = s.toCharArray(); - if (chars.length == 0) - return false; - if (!Character.isJavaIdentifierStart(chars[0])) - return false; - for(int i=1; i<chars.length; i++) { - if (!Character.isJavaIdentifierPart(chars[i])) - return false; - } - return true; - } - //XXX: this can probably go away now that we can probably just copy the list. private List<String> toNameAr(List names,boolean nullok) { int sz = names.size(); @@ -423,7 +411,7 @@ code.id = codes.size(); //Better names in the future? - if (isJavaIdentifier(name)) + if (StringUtil.isJavaIdentifier(name)) code.fname = name+"$"+code.id; else code.fname = "f$"+code.id; @@ -549,7 +537,7 @@ c.invokestatic("org/python/core/Py", "runMain", "(" + bootstrap + $strArr + ")V"); c.return_(); } - + public void addBootstrap() throws IOException { Code c = classfile.addMethod(CodeLoader.GET_BOOTSTRAP_METHOD_NAME, "()" + Type.getDescriptor(CodeBootstrap.class), @@ -655,7 +643,7 @@ String name, String filename, boolean linenumbers, boolean printResults, CompilerFlags cflags) - throws Exception + throws Exception { compile(node, ostream, name, filename, linenumbers, printResults, cflags, org.python.core.imp.NO_MTIME); } Modified: trunk/jython/src/org/python/core/MakeProxies.java =================================================================== --- trunk/jython/src/org/python/core/MakeProxies.java 2009-07-12 00:53:25 UTC (rev 6531) +++ trunk/jython/src/org/python/core/MakeProxies.java 2009-07-12 05:41:43 UTC (rev 6532) @@ -8,6 +8,7 @@ import org.python.compiler.AdapterMaker; import org.python.compiler.JavaMaker; +import org.python.core.util.StringUtil; class MakeProxies { @@ -51,13 +52,24 @@ List<Class<?>> vinterfaces, String className, String proxyName, PyObject dict) { Class<?>[] interfaces = vinterfaces.toArray(new Class<?>[vinterfaces.size()]); - String fullProxyName = proxyPrefix + proxyName + "$" + proxyNumber++; + String fullProxyName; + PyObject customProxyName = dict.__finditem__("__javaname__"); + if (customProxyName != null) { + fullProxyName = Py.tojava(customProxyName, String.class); + if (!StringUtil.isJavaClassName(fullProxyName)) { + throw Py.TypeError(fullProxyName + " isn't a valid Java class name. Classes " + + "must be valid Java identifiers: " + + "http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#40625"); + } + } else { + fullProxyName = proxyPrefix + proxyName + "$" + proxyNumber++; + } String pythonModuleName; PyObject mn = dict.__finditem__("__module__"); if (mn == null) { pythonModuleName = "foo"; } else { - pythonModuleName = (String) mn.__tojava__(String.class); + pythonModuleName = Py.tojava(mn, String.class); } JavaMaker jm = new JavaMaker(superclass, interfaces, Modified: trunk/jython/src/org/python/core/PyType.java =================================================================== --- trunk/jython/src/org/python/core/PyType.java 2009-07-12 00:53:25 UTC (rev 6531) +++ trunk/jython/src/org/python/core/PyType.java 2009-07-12 05:41:43 UTC (rev 6532) @@ -579,11 +579,9 @@ if (module != null) { proxyName = module.toString() + "$" + proxyName; } - Class<?> proxyClass = MakeProxies.makeProxy(baseProxyClass, interfaces, name, proxyName, - dict); - javaProxy = proxyClass; + javaProxy = MakeProxies.makeProxy(baseProxyClass, interfaces, name, proxyName, dict); - PyType proxyType = PyType.fromClass(proxyClass); + PyType proxyType = PyType.fromClass((Class<?>)javaProxy); List<PyObject> cleanedBases = Generic.list(); boolean addedProxyType = false; for (PyObject base : bases) { Modified: trunk/jython/src/org/python/core/util/StringUtil.java =================================================================== --- trunk/jython/src/org/python/core/util/StringUtil.java 2009-07-12 00:53:25 UTC (rev 6531) +++ trunk/jython/src/org/python/core/util/StringUtil.java 2009-07-12 05:41:43 UTC (rev 6532) @@ -3,8 +3,10 @@ import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; +import java.util.Set; import org.python.core.Py; +import org.python.util.Generic; /** * String Utility methods. @@ -84,4 +86,47 @@ chars[0] = Character.toLowerCase(c0); return new String(chars); } + + /** + * Returns true if each segment of <code>name</code> produced by splitting it on '.' is a valid + * Java identifier. + */ + public static boolean isJavaClassName(String name) { + for (String segment : name.split("\\.")) { + if (!isJavaIdentifier(segment)) { + return false; + } + } + return true; + } + + /** + * Returns true if ident is a valid Java identifier as defined by + * http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#40625 + */ + public static boolean isJavaIdentifier(String ident) { + if (ident.isEmpty() || JAVA_LITERALS.contains(ident)) { + return false; + } + int cp = ident.codePointAt(0); + if (!Character.isJavaIdentifierStart(cp)) { + return false; + } + for (int i = Character.charCount(cp); i < ident.length(); i += Character.charCount(cp)) { + cp = ident.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp)) { + return false; + } + } + return true; + } + + // True false and null are just literals, the rest are keywords + private static final Set<String> JAVA_LITERALS = Generic.set("abstract", "continue", "for", + "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do", + "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", + "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", + "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", + "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", + "while", "true", "false", "null"); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |