1

(bean obj)Clojure を使用して、オブジェクトに関連する不変のマップを取得しようとしています。

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。クラス")。

これはどのように修正できますか?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

This issue can be solved by searching the inheritance tree for a public class or interface containing the same method. In Clojure, this can be implemented (albeit with poor performance) as follows:

(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)))))

...and then calling .invoke on (public-version-of-method m) rather than m (if it returns a non-nil value), or accepting that the method is not publicly accessible if this method returns a nil value.

(The above code has been submitted upstream as part of a proposed patch for CLJ-978).

于 2012-05-01T03:37:28.120 に答える