Allow access to public members of private inner classes where possible
This commit is contained in:
16
README.html
16
README.html
@@ -469,6 +469,18 @@ Time is a represented as number of milliseconds since the epoch,
|
||||
and most time and date formatting, locales, and other features
|
||||
are not implemented.
|
||||
|
||||
<h3>Coroutine Library</h3>
|
||||
The <em>coroutine</em> library is implemented using one JavaThread per coroutine.
|
||||
This allows <em>coroutine.yield()</em> can be called from anywhere,
|
||||
as with the yield-from-anywhere patch in C-based lua.
|
||||
|
||||
<p>
|
||||
Luaj uses WeakReferences and the OrphanedThread error to ensure that coroutines that are no longer referenced
|
||||
are properly garbage collected. For thread safety, OrphanedThread should not be caught by Java code.
|
||||
See <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/LuaThread.html">LuaThread</a>
|
||||
and <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/OrphanedThread.html">OrphanedThread</a>
|
||||
javadoc for details.
|
||||
|
||||
<h3>Debug Library</h3>
|
||||
The <em>debug</em> library is not included by default by
|
||||
<em>JmePlatform.standardGlobals()</em> or <em>JsePlatform.standardGlobsls()</em> .
|
||||
@@ -505,7 +517,7 @@ See a longer sample in <em>examples/lua/swingapp.lua</em> for details, or try ru
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The Java ME platform does not include this library, and it cannot be made to work because of the lack of a reflection API in Java SE.
|
||||
The Java ME platform does not include this library, and it cannot be made to work because of the lack of a reflection API in Java ME.
|
||||
|
||||
<p>
|
||||
The <em>lua</em> connand line tool includes <em>luajava</em>.
|
||||
@@ -734,6 +746,7 @@ and LuaForge:
|
||||
<li>Fix lua command vararg values passed into main script to match what is in global arg table </li>
|
||||
<li>Add arithmetic metatag processing when left hand side is a number and right hand side has metatable </li>
|
||||
<li>Fix load(func) when mutiple string fragments are supplied by calls to func </li>
|
||||
<li>Allow access to public members of private inner classes where possible </li>
|
||||
</ul></td></tr>
|
||||
</table></td></tr></table>
|
||||
|
||||
@@ -744,5 +757,6 @@ and LuaForge:
|
||||
<li>using both version 1 and 2 libraries together in the same java vm has not been tested
|
||||
<li>module() and setfenv() only partially supported for lau2java or luajc compiled lua
|
||||
<li>values associated with weak keys may linger longer than expected
|
||||
<li>behavior of luaj when a SecurityManager is used has not been fully characterized
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -47,12 +47,12 @@ import org.luaj.vm2.lib.DebugLib;
|
||||
* The behavior of coroutine threads matches closely the behavior
|
||||
* of C coroutine library. However, because of the use of Java threads
|
||||
* to manage call state, it is possible to yield from anywhere in luaj.
|
||||
* On the other hand, if a {@link LuaThread} is created, then yields
|
||||
* without ever entering a completed state, then the garbage collector
|
||||
* may not be able to determine that the thread needs to be collected,
|
||||
* and this could cause a memory and resource leak. It is recommended
|
||||
* that all coroutines that are created are resumed until they are in
|
||||
* a completed state.
|
||||
* <p>
|
||||
* Each Java thread wakes up at regular intervals and checks a weak reference
|
||||
* to determine if it can ever be resumed. If not, it throws
|
||||
* {@link OrphanedThread} which is an {@link java.lang.Error}.
|
||||
* Applications should not catch {@link OrphanedThread}, because it can break
|
||||
* the thread safety of luaj.
|
||||
*
|
||||
* @see LuaValue
|
||||
* @see JsePlatform
|
||||
@@ -64,7 +64,10 @@ public class LuaThread extends LuaValue {
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public static int coroutine_count = 0;
|
||||
|
||||
|
||||
/** Interval at which to check for lua threads that are no longer referenced.
|
||||
* This can be changed by Java startup code if desired.
|
||||
*/
|
||||
static long thread_orphan_check_interval = 30000;
|
||||
|
||||
private static final int STATUS_INITIAL = 0;
|
||||
|
||||
@@ -21,19 +21,20 @@
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
/**
|
||||
* Error sublcass that indicates a lua thread that is no longer referenced has been detected.
|
||||
*
|
||||
* The java thread in which this is thrown should correspond to a LuaThread being used as a
|
||||
* coroutine that could not possibly be resumed again because there are no more references
|
||||
* to the LuaThread with which it is associated. Rather than locking up resources forever,
|
||||
* this error is thrown, and should fall through all the way to the thread's run() method.
|
||||
*
|
||||
* Java code mixed with the luaj vm should not catch this error because it may occur when
|
||||
* the coroutine is not running, so any processing done during error handling could break
|
||||
* the thread-safety of the application because other lua processing could be going on in
|
||||
* a different thread.
|
||||
/**
|
||||
* {@link java.lang.Error} sublcass that indicates a lua thread that is no
|
||||
* longer referenced has been detected.
|
||||
* <p>
|
||||
* The java thread in which this is thrown should correspond to a
|
||||
* {@link LuaThread} being used as a coroutine that could not possibly be
|
||||
* resumed again because there are no more references to the LuaThread with
|
||||
* which it is associated. Rather than locking up resources forever, this error
|
||||
* is thrown, and should fall through all the way to the thread's {@link Thread.run}() method.
|
||||
* <p>
|
||||
* Java code mixed with the luaj vm should not catch this error because it may
|
||||
* occur when the coroutine is not running, so any processing done during error
|
||||
* handling could break the thread-safety of the application because other lua
|
||||
* processing could be going on in a different thread.
|
||||
*/
|
||||
public class OrphanedThread extends Error {
|
||||
|
||||
|
||||
@@ -76,9 +76,17 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
|
||||
if ( fields == null ) {
|
||||
Map m = new HashMap();
|
||||
Field[] f = ((Class)m_instance).getFields();
|
||||
for ( int i=0; i<f.length; i++ )
|
||||
if ( Modifier.isPublic(f[i].getModifiers()) )
|
||||
m.put( LuaValue.valueOf(f[i].getName()), f[i] );
|
||||
for ( int i=0; i<f.length; i++ ) {
|
||||
Field fi = f[i];
|
||||
if ( Modifier.isPublic(fi.getModifiers()) ) {
|
||||
m.put( LuaValue.valueOf(fi.getName()), fi );
|
||||
try {
|
||||
if (!fi.isAccessible())
|
||||
fi.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
}
|
||||
fields = m;
|
||||
}
|
||||
return (Field) fields.get(key);
|
||||
|
||||
@@ -63,6 +63,11 @@ class JavaMethod extends JavaMember {
|
||||
private JavaMethod(Method m) {
|
||||
super( m.getParameterTypes(), m.getModifiers() );
|
||||
this.method = m;
|
||||
try {
|
||||
if (!m.isAccessible())
|
||||
m.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.luaj.vm2.compiler.DumpLoadEndianIntTest;
|
||||
import org.luaj.vm2.compiler.RegressionTests;
|
||||
import org.luaj.vm2.compiler.SimpleTests;
|
||||
import org.luaj.vm2.lib.jse.LuaJavaCoercionTest;
|
||||
import org.luaj.vm2.lib.jse.LuajavaAccessibleMembersTest;
|
||||
import org.luaj.vm2.lib.jse.LuajavaClassMembersTest;
|
||||
import org.luaj.vm2.vm1.Luajvm1CompatibilityTest;
|
||||
|
||||
@@ -74,6 +75,7 @@ public class AllTests {
|
||||
|
||||
// library tests
|
||||
TestSuite lib = new TestSuite("Library Tests");
|
||||
lib.addTestSuite(LuajavaAccessibleMembersTest.class);
|
||||
lib.addTestSuite(LuajavaClassMembersTest.class);
|
||||
lib.addTestSuite(LuaJavaCoercionTest.class);
|
||||
lib.addTestSuite(RequireClassTest.class);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.Permission;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
public class LuajavaAccessibleMembersTest extends TestCase {
|
||||
|
||||
private LuaTable _G;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
_G = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
private String invokeScript(String script) {
|
||||
try {
|
||||
InputStream is = new ByteArrayInputStream( script.getBytes("UTF8") );
|
||||
LuaFunction c = LuaC.instance.load( is, "script", _G );
|
||||
return c.call().tojstring();
|
||||
} catch ( Exception e ) {
|
||||
fail("exception: "+e );
|
||||
return "failed";
|
||||
}
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassImplementedMethod() {
|
||||
assertEquals("privateImpl-aaa-interface_method(bar)", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"return a:interface_method('bar');"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassPublicMethod() {
|
||||
assertEquals("privateImpl-aaa-public_method", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"return a:public_method();"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassGetPublicField() {
|
||||
assertEquals("aaa", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"return a.public_field;"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassSetPublicField() {
|
||||
assertEquals("foo", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"a.public_field = 'foo';" +
|
||||
"return a.public_field;"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassPublicConcstructor() {
|
||||
assertEquals("privateImpl-constructor", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"c = b:get_PrivateImplClass();" +
|
||||
"return luajava.new(c);"));
|
||||
}
|
||||
}
|
||||
18
test/junit/org/luaj/vm2/lib/jse/TestClass.java
Normal file
18
test/junit/org/luaj/vm2/lib/jse/TestClass.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
public class TestClass {
|
||||
private static class PrivateImpl implements TestInterface {
|
||||
public String public_field;
|
||||
public PrivateImpl() {
|
||||
this.public_field = "privateImpl-constructor";
|
||||
}
|
||||
PrivateImpl(String f) {
|
||||
this.public_field = f;
|
||||
}
|
||||
public String public_method() { return "privateImpl-"+public_field+"-public_method"; }
|
||||
public String interface_method(String x) { return "privateImpl-"+public_field+"-interface_method("+x+")"; }
|
||||
public String toString() { return public_field; }
|
||||
}
|
||||
public TestInterface create_PrivateImpl(String f) { return new PrivateImpl(f); }
|
||||
public Class get_PrivateImplClass() { return PrivateImpl.class; }
|
||||
}
|
||||
5
test/junit/org/luaj/vm2/lib/jse/TestInterface.java
Normal file
5
test/junit/org/luaj/vm2/lib/jse/TestInterface.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
public interface TestInterface {
|
||||
String interface_method(String x);
|
||||
}
|
||||
Reference in New Issue
Block a user