2012-04-30 5 views
1

Clojure의 (bean obj)을 사용하여 개체와 관련된 불변 맵을 검색하려고합니다. Clojure의 1.4.0 표준 라이브러리에서 java.bean API를 사용하여 비공개 클래스의 인스턴스 검사

, 이것은 너무 (의사 코드로 변환 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 구현에서 비공개 메소드를 반환하지 않습니다. 그러나 검사 대상 객체가 비공개 클래스의 인스턴스 인 경우 해당 클래스에 대한 public 메소드를 반환합니다. 실제로는 호출 할 수 없지만 IllegalArgumentException ("비공개 클래스의 public 메소드는 호출 할 수 없습니다. public class ").

어떻게이 문제를 해결할 수 있습니까? 내가 java.lang.Class에 대한 설명서를보고 있는데, try/catch 블록을 포함하지 않는 클래스 사용 권한을 확인하는 확실한 방법이 보이지 않는다. java.lang.SecurityException ... 정확하게 어떤 것일까? 모범 사례. 게다가, 비 public 클래스의 메소드가 public 인터페이스를 구현하는 경우,이 메소드를 안전하게 호출 할 수 있을지 어떨지를 판별 할 수있는기구가 제공되지 않으면 안됩니다.

답변

2

는 클래스에 수정을 발견 할 수 있기 때문에이 같은 것을 사용하면 객체가이 문제를 해결할 수 있습니다

public boolean isInstanceOfPrivateClass(Object o) { 
    return Modifier.isPrivate(o.getClass().getModifiers()); 
} 
+0

불행히도 개인 클래스가 공용 인터페이스를 구현하는 경우이 대답은 그 인터페이스를 통해 정의 된 메서드에 액세스 할 수 있는지를 결정하기에 충분하지 않습니다. PropertyDescriptor에서 인터페이스를 식별하는 방법과 함께, 아마도 충분할 것입니다. –

+0

오브젝트가 인터페이스 (정의에 의해 public)를 구현하는 클래스 인 경우, 클래스의 프라이버시에 관계없이 인터페이스에서 메소드를 호출 할 수 있어야합니다. 다른 것은 버그입니다. Java에는 내부 클래스가 언어에 추가 된 방식으로 인한 많은 불필요한 수하물이 있습니다. 개인 클래스는 내부 클래스로만 의미가 있습니다. 내가 누락 된 예제의 구조에 뭔가가있을 수 있습니다. – sw1nn

+0

나는 공개 메서드가있는 비공개 클래스가 있습니다. 이러한 메소드 중 일부는 인터페이스를 구현하는 클래스에 의해 공개적으로 호출 될 수 있습니다. 이러한 공용 메소드 중 일부는 공용 클래스 나 인터페이스에 의해 정의되지 않기 때문에 호출 할 수 없으며 비공개 클래스 내에서만 호출 할 수 있습니다. 이것을 유도하는 실제 사용 사례는 Jira에서 사용 된 Atlassian의 Crowd 제품의'com.atlassian.crowd.embedded.ofbiz.OfBizUser'입니다. 나는 그들이 비공개 수업에 대한 공개 방법을 갖는 것이 이치에 맞지 않는다는 것에 동의하지만, 그 점에 대한 나의 유일한 통제는 많은 것을 제안하는 티켓을 제출하는 것입니다. –

1

개인 클래스의 인스턴스 (주로 테스트하지)인지 확인할 수 있도록해야한다 상속 트리에서 동일한 메소드를 포함하는 공용 클래스 또는 인터페이스를 검색하는 것. (가 nil이 아닌 값을 반환하는 경우)보다는 m(public-version-of-method m).invoke를 호출 한 후

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

...와, 또는 것을 받아들이 : Clojure에,이 다음과 같이 (성능 저하이기는하지만) 구현 될 수 이 메서드가 nil 값을 반환하면 메서드에 공개적으로 액세스 할 수 없습니다.

(위의 코드는 CLJ-978에 대한 제안 된 패치의 일부로 업스트림으로 제출되었습니다).

+1

+1 - 어렵지 않아야합니다 :-), 참고로 아파치 commons-beanutils는 http://www.docjar.com/html/api/org/apache/commons/beanutils/MethodUtils.java와 비슷합니다. html # 771 – sw1nn

+0

@ sw1nn Apache Commons 구현을 지적 해 주셔서 감사합니다. 매우 도움이됩니다! –

관련 문제