2013-12-20 2 views
0

Если я передаю объект Rhino в Java, есть ли аннотация, которую я могу использовать в классе этого объекта, чтобы скрыть методы \ поля из Rhino JavaScripts, чтобы сделать их недоступными для JavaScripts? Или любой другой способ сделать это?Как скрыть метод класса из Rhino Script Engine?

Я провел некоторое исследование, и похоже, что я мог бы обернуть объекты со сценарием, но это похоже на более грязное решение, чем то, что может быть действительно очень легко сделать, поскольку кажется, что это будет довольно стандартная функция.

Спасибо.

ответ

2

Я не смог найти какую-либо поддержку для этого в двигателе Rhino (если кто-нибудь знают о таких вещах, пожалуйста, так сказать.)

Это, как правило, легко реализовать. Вам необходимо реализовать собственный WrapFactory и собственный NativeJavaObject. Вам также нужно вызвать создать собственный ContextFactory, чтобы гарантировать, что ваш WrapFactory используется во всех объектах Context, используемых во всем движке сценария. Это звучит как много работы ... но на самом деле это на самом деле просто много кода обертки. Вот фрагмент моей реализации. ЧТО ПРОИСХОДИТ: фактический вызов ContextFactory.initGlobal для установки глобальной ContextFactory для вашей реализации ContextFactory.

Очевидно, что этот код не поточно

class ProtectedContextFactory extends ContextFactory 
{ 
    private static final ProtectedWrapFactory wrapper = new ProtectedWrapFactory(); 

    @Override 
    protected Context makeContext() 
    { 
     Context c = super.makeContext(); 
     c.setWrapFactory(wrapper); 

     return c; 
    } 
} 

class ProtectedWrapFactory extends WrapFactory 
{ 
    @Override 
    public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class<?> staticType) 
    { 
     return new ProtectedNativeJavaObject(scope, javaObject, staticType); 
    } 
} 

class ProtectedNativeJavaObject extends NativeJavaObject 
{ 
    private static final HashMap<Class<?>, ArrayList<String>> CLASS_PROTECTION_CACHE = new HashMap<Class<?>, ArrayList<String>>(); 

    private ArrayList<String> m_protectedMembers; 

    public ProtectedNativeJavaObject(Scriptable scope, Object javaObject, Class<?> staticType) 
    { 
     super(scope, javaObject, staticType); 

     Class<?> clazz = javaObject != null ? javaObject.getClass() : staticType; 

     m_protectedMembers = CLASS_PROTECTION_CACHE.get(clazz); 

     if(m_protectedMembers == null) 
      m_protectedMembers = processClass(clazz); 
    } 

    private static ArrayList<String> processClass(Class<?> clazz) 
    { 
     ArrayList<String> protectedMethods = new ArrayList<String>(); 

     CLASS_PROTECTION_CACHE.put(clazz, protectedMethods); 

     for(Method m : clazz.getMethods()) 
     { 
      if(m.getAnnotation(ScriptHiddenMember.class) != null) 
       protectedMethods.add(m.getName()); 
     } 

     for(Field f : clazz.getFields()) 
     { 
      if(f.getAnnotation(ScriptHiddenMember.class) != null) 
       protectedMethods.add(f.getName()); 
     } 
     return protectedMethods; 
    } 

    @Override 
    public boolean has(String name, Scriptable start) 
    { 
     if(m_protectedMembers.contains(name)) 
      return false; 
     else 
      return super.has(name, start); 
    } 

    @Override 
    public Object get(String name, Scriptable start) 
    { 
     if(m_protectedMembers.contains(name)) 
      return NOT_FOUND; 
     else 
      return super.get(name, start); 
    } 
} 

@Target({ElementType.METHOD, ElementType.FIELD}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface ScriptHiddenMember {} 
0

Почему вы не пытаетесь использовать интерфейсы Java. Для каждого класса, который будет представлен Rhino, определите интерфейс, который содержит геттеры и сеттеры для полей, которые вы хотите открыть, и методы, которые вы хотите открыть.

Подробнее о том, как получить доступ к Java-интерфейсы можно найти на Rhino: Access Java interface variables in Javascript implementation

+0

Я использую внутренний класс (для представления внешний) для обеспечения ограниченного доступа к этому внешнему объекту из сценария. Проблема в том, что скрипт может захотеть ссылаться на этот внешний объект при вызове другого метода Java. Таким образом, метод Java будет иметь только экземпляр для внутреннего класса для работы (поскольку вызывающий скрипт имеет доступ только к внутреннему классу.) Теперь мне нужно перейти от внутреннего класса (который представляет его внешний класс к скриптам) к внешнему классу, чтобы он мог использоваться без ограничений с помощью метода. Проблема в том, что для получения этого внешнего объекта мне нужно открыть метод ... – Jeremy

+0

(который я хочу скрыть от сценария, чтобы он не мог получить доступ к внешнему объекту) во внутреннем классе, который вернет экземпляр в внешний объект, который может использоваться вызываемым java-методом. Я могу привести пример, если мое объяснение трудно выполнить. – Jeremy

+0

Вы считали использование интерфейса вместо внутреннего класса? – user987339

2

Используя интерфейс и скрытие методы, не включая их в интерфейсе не будет работать, то сценарий будет по-прежнему иметь возможность доступа к методам без подписи в интерфейс, даже когда вы добавляете объект в движок, пока вы добавляете его в свой интерфейс. То, как я нашел, чтобы скрыть методы, - объявить их частными, защищенными или (без модификатора); это позволяет сценарию получить доступ. Если вы используете protected или (без модификатора), то вы все равно можете использовать их в своем коде в других классах (при условии, что вы вызываете их из допустимого места) при их скрытии от JS.

Для переменных, если вы объявляете их частными, защищенными или (без модификатора), и не включают в себя какие-либо методы getter, переменная будет скрыта. Публичные переменные доступны даже без методов getter.

С помощью этого интерфейса:

public interface NodeInterface { 

    public int getPosition(); 

} 

И этот реализующий класс:

public class Node implements NodeInterface{ 

    private int x = 5; 

    public int y = 8; 

    private int position = 0; 

    public int getPosition(){return position;} 

    private String getString(){return "hello";} 

    public String getBing(){return "bing";} 

} 

Результаты в этом коде:

ScriptEngineManager factory = new ScriptEngineManager(); 
ScriptEngine engine = factory.getEngineByName("JavaScript"); 
NodeInterface node = (NodeInterface)new Node(); 
engine.put("node", node); 
try { 
    engine.eval("println(node.x)");//undefined 
    engine.eval("println(node.y)");//8 
    engine.eval("println(node.position)");//0 
    engine.eval("println(node.getPosition())");//0 
    engine.eval("println(node.getBing());");//hello 
    engine.eval("println(node.getString())");//TypeError: Cannot find function getString. 
} catch (ScriptException e1) { 
    e1.printStackTrace(); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^