Implemented issue: #82

This commit is contained in:
UnlegitDqrk
2026-03-02 13:48:14 +01:00
parent 572fd95692
commit ff4033cad4
35 changed files with 141 additions and 13 deletions

View File

@@ -56,6 +56,10 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
Map methods; Map methods;
Map innerclasses; Map innerclasses;
static void flushClassCache() {
classes.clear();
}
static JavaClass forClass(Class c) { static JavaClass forClass(Class c) {
JavaClass j = (JavaClass) classes.get(c); JavaClass j = (JavaClass) classes.get(c);
if ( j == null ) if ( j == null )
@@ -75,10 +79,11 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
Field getField(LuaValue key) { Field getField(LuaValue key) {
if ( fields == null ) { if ( fields == null ) {
Map m = new HashMap(); Map m = new HashMap();
Field[] f = ((Class)m_instance).getFields(); Class clazz = (Class) m_instance;
Field[] f = clazz.getFields();
for ( int i=0; i<f.length; i++ ) { for ( int i=0; i<f.length; i++ ) {
Field fi = f[i]; Field fi = f[i];
if ( Modifier.isPublic(fi.getModifiers()) ) { if ( Modifier.isPublic(fi.getModifiers()) && LuajavaLib.isFieldVisible(clazz, fi) ) {
m.put(LuaValue.valueOf(fi.getName()), fi); m.put(LuaValue.valueOf(fi.getName()), fi);
try { try {
if (!fi.isAccessible()) if (!fi.isAccessible())
@@ -95,10 +100,11 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
LuaValue getMethod(LuaValue key) { LuaValue getMethod(LuaValue key) {
if ( methods == null ) { if ( methods == null ) {
Map namedlists = new HashMap(); Map namedlists = new HashMap();
Method[] m = ((Class)m_instance).getMethods(); Class clazz = (Class) m_instance;
Method[] m = clazz.getMethods();
for ( int i=0; i<m.length; i++ ) { for ( int i=0; i<m.length; i++ ) {
Method mi = m[i]; Method mi = m[i];
if ( Modifier.isPublic( mi.getModifiers()) ) { if ( Modifier.isPublic( mi.getModifiers()) && LuajavaLib.isMethodVisible(clazz, mi) ) {
String name = mi.getName(); String name = mi.getName();
List list = (List) namedlists.get(name); List list = (List) namedlists.get(name);
if ( list == null ) if ( list == null )
@@ -107,10 +113,10 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
} }
} }
Map map = new HashMap(); Map map = new HashMap();
Constructor[] c = ((Class)m_instance).getConstructors(); Constructor[] c = clazz.getConstructors();
List list = new ArrayList(); List list = new ArrayList();
for ( int i=0; i<c.length; i++ ) for ( int i=0; i<c.length; i++ )
if ( Modifier.isPublic(c[i].getModifiers()) ) if ( Modifier.isPublic(c[i].getModifiers()) && LuajavaLib.isConstructorVisible(clazz, c[i]) )
list.add( JavaConstructor.forConstructor(c[i]) ); list.add( JavaConstructor.forConstructor(c[i]) );
switch ( list.size() ) { switch ( list.size() ) {
case 0: break; case 0: break;
@@ -135,12 +141,15 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
Class getInnerClass(LuaValue key) { Class getInnerClass(LuaValue key) {
if ( innerclasses == null ) { if ( innerclasses == null ) {
Map m = new HashMap(); Map m = new HashMap();
Class[] c = ((Class)m_instance).getClasses(); Class clazz = (Class) m_instance;
Class[] c = clazz.getClasses();
for ( int i=0; i<c.length; i++ ) { for ( int i=0; i<c.length; i++ ) {
Class ci = c[i]; Class ci = c[i];
String name = ci.getName(); if (LuajavaLib.isInnerClassVisible(clazz, ci)) {
String stub = name.substring(Math.max(name.lastIndexOf('$'), name.lastIndexOf('.'))+1); String name = ci.getName();
m.put(LuaValue.valueOf(stub), ci); String stub = name.substring(Math.max(name.lastIndexOf('$'), name.lastIndexOf('.'))+1);
m.put(LuaValue.valueOf(stub), ci);
}
} }
innerclasses = m; innerclasses = m;
} }

View File

@@ -23,6 +23,8 @@ package org.luaj.vm2.libs.jse;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -83,6 +85,38 @@ import org.luaj.vm2.libs.VarArgFunction;
*/ */
public class LuajavaLib extends VarArgFunction { public class LuajavaLib extends VarArgFunction {
public interface VisibilityPolicy {
boolean isClassVisible(Class clazz);
boolean isInnerClassVisible(Class owner, Class innerClass);
boolean isFieldVisible(Class owner, Field field);
boolean isMethodVisible(Class owner, Method method);
boolean isConstructorVisible(Class owner, Constructor constructor);
}
private static final VisibilityPolicy PUBLIC_MEMBERS_POLICY = new VisibilityPolicy() {
public boolean isClassVisible(Class clazz) {
return true;
}
public boolean isInnerClassVisible(Class owner, Class innerClass) {
return true;
}
public boolean isFieldVisible(Class owner, Field field) {
return true;
}
public boolean isMethodVisible(Class owner, Method method) {
return true;
}
public boolean isConstructorVisible(Class owner, Constructor constructor) {
return true;
}
};
private static volatile VisibilityPolicy visibilityPolicy = PUBLIC_MEMBERS_POLICY;
static final int INIT = 0; static final int INIT = 0;
static final int BINDCLASS = 1; static final int BINDCLASS = 1;
static final int NEWINSTANCE = 2; static final int NEWINSTANCE = 2;
@@ -103,6 +137,35 @@ public class LuajavaLib extends VarArgFunction {
public LuajavaLib() { public LuajavaLib() {
} }
public static void setVisibilityPolicy(VisibilityPolicy policy) {
visibilityPolicy = policy != null ? policy : PUBLIC_MEMBERS_POLICY;
JavaClass.flushClassCache();
}
public static VisibilityPolicy getVisibilityPolicy() {
return visibilityPolicy;
}
static boolean isClassVisible(Class clazz) {
return visibilityPolicy.isClassVisible(clazz);
}
static boolean isInnerClassVisible(Class owner, Class innerClass) {
return visibilityPolicy.isInnerClassVisible(owner, innerClass);
}
static boolean isFieldVisible(Class owner, Field field) {
return visibilityPolicy.isFieldVisible(owner, field);
}
static boolean isMethodVisible(Class owner, Method method) {
return visibilityPolicy.isMethodVisible(owner, method);
}
static boolean isConstructorVisible(Class owner, Constructor constructor) {
return visibilityPolicy.isConstructorVisible(owner, constructor);
}
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
try { try {
switch ( opcode ) { switch ( opcode ) {
@@ -117,6 +180,8 @@ public class LuajavaLib extends VarArgFunction {
} }
case BINDCLASS: { case BINDCLASS: {
final Class clazz = classForName(args.checkjstring(1)); final Class clazz = classForName(args.checkjstring(1));
if (!isClassVisible(clazz))
throw new LuaError("class is not visible: " + clazz.getName());
return JavaClass.forClass(clazz); return JavaClass.forClass(clazz);
} }
case NEWINSTANCE: case NEWINSTANCE:
@@ -124,6 +189,8 @@ public class LuajavaLib extends VarArgFunction {
// get constructor // get constructor
final LuaValue c = args.checkvalue(1); final LuaValue c = args.checkvalue(1);
final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class)); final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));
if (!isClassVisible(clazz))
throw new LuaError("class is not visible: " + clazz.getName());
final Varargs consargs = args.subargs(2); final Varargs consargs = args.subargs(2);
return JavaClass.forClass(clazz).getConstructor().invoke(consargs); return JavaClass.forClass(clazz).getConstructor().invoke(consargs);
} }
@@ -175,7 +242,10 @@ public class LuajavaLib extends VarArgFunction {
// load classes using app loader to allow luaj to be used as an extension // load classes using app loader to allow luaj to be used as an extension
protected Class classForName(String name) throws ClassNotFoundException { protected Class classForName(String name) throws ClassNotFoundException {
return Class.forName(name, true, ClassLoader.getSystemClassLoader()); Class clazz = Class.forName(name, true, ClassLoader.getSystemClassLoader());
if (!isClassVisible(clazz))
throw new ClassNotFoundException("class is not visible: " + name);
return clazz;
} }
private static final class ProxyInvocationHandler implements InvocationHandler { private static final class ProxyInvocationHandler implements InvocationHandler {

View File

@@ -1,5 +1,9 @@
package org.luaj.vm2.libs.jse; package org.luaj.vm2.libs.jse;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.luaj.vm2.LuaError; import org.luaj.vm2.LuaError;
@@ -235,4 +239,49 @@ public class LuajavaClassMembersTest extends TestCase {
LuaValue e = ic.get("E"); LuaValue e = ic.get("E");
assertTrue(e.isnil()); assertTrue(e.isnil());
} }
public void testVisibilityPolicyCanRestrictVisibleMembers() {
LuajavaLib.VisibilityPolicy previous = LuajavaLib.getVisibilityPolicy();
try {
LuajavaLib.setVisibilityPolicy(new LuajavaLib.VisibilityPolicy() {
public boolean isClassVisible(Class clazz) {
return clazz == B.class || clazz == C.class || clazz == C.D.class;
}
public boolean isInnerClassVisible(Class owner, Class innerClass) {
return innerClass == C.D.class;
}
public boolean isFieldVisible(Class owner, Field field) {
return "m_int_field".equals(field.getName());
}
public boolean isMethodVisible(Class owner, Method method) {
String name = method.getName();
return "getint".equals(name) || "pick".equals(name);
}
public boolean isConstructorVisible(Class owner, Constructor constructor) {
return owner == B.class && constructor.getParameterTypes().length == 0;
}
});
JavaInstance instance = new JavaInstance(new B());
assertFalse(instance.get("m_int_field").isnil());
assertTrue(instance.get("m_string_field").isnil());
assertFalse(instance.get("getint").isnil());
assertTrue(instance.get("getString").isnil());
JavaClass bClass = JavaClass.forClass(B.class);
assertFalse(bClass.get("new").isnil());
JavaClass cClass = JavaClass.forClass(C.class);
assertTrue(cClass.get("new").isnil());
JavaInstance cInstance = new JavaInstance(new C());
assertFalse(cInstance.get("D").isnil());
} finally {
LuajavaLib.setVisibilityPolicy(previous);
}
}
} }