1

我正在尝试使用 Clojure(bean obj)检索与对象相关的不可变映射。

在 Clojure 1.4.0 标准库中,这大致是这样实现的(翻译成不熟悉 Clojure 的人可以访问的伪代码):

import java.beans.PropertyDescriptor;
import java.beans.Introspector;

function introspect(Object obj) {
  Class clazz = obj.getClass();
  PropertyDescriptor descriptors[] =
    Introspector
    .getBeanInfo(clazz)
    .getPropertyDescriptors();
  Map retval = new HashMap();

  for(pd in descriptors) {
    name = pd.getName();
    method = pd.getReadMethod();
    if(method.getParameterTypes().length != 0)
      continue;
    retval.set(name, method.invoke(obj, nil));
  }
  /* the real implementation does more magic below here,
     but the above is sufficient for this question */
  return retval;
}

在大多数情况下,这很好用—— java.bean.Introspector在其默认的BeanInfo实现中不返回非公共方法。但是,当被检查的对象是非公共类的实例时,它会返回该类的公共方法——即使这些方法实际上不能在不引发IllegalArgumentException("Can't call public method of non-public班级”)。

如何解决这个问题?我正在查看java.lang.Class的文档,但我没有看到一种明显的方法来确定不涉及java.lang.SecurityException的 try/catch 块的类的权限......我认为这可能是最佳实践。此外,在非公共类上的方法实现公共接口的情况下,应该有某种机制来确定可以安全地调用该方法。

4

2 回答 2

2

您可以在类上发现修饰符,因此这样的事情应该允许您检查对象是否是私有类的实例(未经过大量测试)

public boolean isInstanceOfPrivateClass(Object o) {
    return Modifier.isPrivate(o.getClass().getModifiers());
}
于 2012-04-30T18:52:16.477 回答
1

可以通过在继承树中搜索包含相同方法的公共类或接口来解决此问题。在 Clojure 中,这可以按如下方式实现(尽管性能很差):

(defn- public-version-of-method [^Method method]
   "returns a Method built against a public interface or superclass
   declaring this method, or nil if none exists"
   (let [sig (method-sig method)]
     (loop [current-class (. method (getDeclaringClass))
            pending-supers (seq (supers current-class))]
       (if (and current-class
                (Modifier/isPublic (.getModifiers current-class))
                (some (fn [x] (= sig (method-sig x)))
                      (. current-class (getDeclaredMethods))))
         (. current-class (getDeclaredMethod
                           (.getName method)
                           (.getParameterTypes method)))
         (if pending-supers
           (recur (first pending-supers)
                  (next pending-supers))
           nil)))))

...然后调用.invoke(public-version-of-method m)不是m(如果它返回非 nil 值),或者如果此方法返回 nil 值,则接受该方法不可公开访问。

(上述代码已作为提议的补丁的一部分提交给上游CLJ-978提议补丁的一部分提交到上游)。

于 2012-05-01T03:37:28.120 回答