Reflection 알고 쓰기

|

요즘 하는 프로젝트에서 맡은부분이 데이터 처리하는쪽이라 아무래도 범용성을 따지게 된다.


구조 자체를 처음부터 내가 잡았다면 내 의도대로 하는게 쉽겠지만,

아무래도 다른 사람이 잡아놓은 구조에 여러 기능을 집어넣어려 하다보니

내가 구상하는 방법과는 다른모양이 많이 보이고....


그렇다보니 자바 리플렉션을 꽤 빈번하게 쓴다.


그 와중에,

필드나 메소드가 public인지 확인하는 목적으로 isAccessible() 메소드를 사용했었는데,

이건 잘못된 사용이란걸 우연히 알게 되었다.


접근자 3가지, public, private, protected의 여부,

즉, 외부에서 접근 가능한 녀석인지 아닌지의 여부는 isAccessible()메소드로 알아낼 수 없다!


접근자를 알아내기 위해서는 getModifier()를 통해 받아온 modifier로 판단한다.

int형으로 반환되는데, 이 반환된 값을 Modifier.isPublic(), isPrivate(), isProtected() 등으로 판단한다.


접근자 외에도 총 11가지의 modifier를 이 값으로 확인할 수 있다.

(친절하게도 문자열형태로 반환해주는 메소드도 있다. Modifier.toString())



그러면, isAccessible() 메소드의 목적은 무엇인가.

이와 쌍으로 setAccessible() 메소드가 있는데, 이 메소드의 이름만 봐도 public같은 접근자와는 상관이 없다는걸 알아야 했는데....

일단 API문서에는 권한이 어쩌구 저쩌구 블라블라..... 라고 설명되어있다.

권한이 무엇이냐... 현재 리플렉션을 쓰는 스레드의 클래스로더와, 리플렉션의 대상이 되는 클래스로더가 달라

접근권한이 없는 경우. 라고 일단은 해석이 된다.

기본적으로 accessible은 false.


클래스로더가 다르다는 말은?


기본적으로 자바 어플리케이션을 구동할 때에는 부트스트랩클래스로더를 통해 JRE 자체적으로 불러오게 된다.

이와는 다르게 다른 클래스로더가 구성될 수 있고, 그 중 jar 파일에서 직접 클래스를 로드할 수 있는 URLClassLoader 라는녀석이 있다.


리플렉션을 사용하는 코드와 동일한 클래스로더를 통해 로드된 클래스는 setAccessible()을 통해 접근가능여부를 제어할 수 있으나

다른 클래스로더의 클래스는 일단 접근이 불가능한것으로 이해. (하지만 Permission을 조정할 수 있는것으로 보아 접근가능하게 설정할 수도 있는듯)


내 클래스로더를 통해 로드되었고, public 필드나 메소드인데도 isAccessible()은 false가 리턴된다.

하지만 이 경우에도 invoke()나 get()메소드를 통해 값을 가져올 수 있다.

private나 protected메소드/필드의 경우에는 setAccessible(true) 로 접근권한을 제어한 후 접근이 가능하다.

(Reflection으로 private/protected 요소에 접근할 수 있다는 말.)



그리고 추가로 덧붙이자면,

필드를 가져오는 getFields() / getDeclaredFields()

메소드를 가져오는 getMethods() / getDeclaredMethods()

등등


Declared가 붙은 녀석이 있고 없는 녀석이 있는데,

이 둘의 차이점은 Declared가 붙어있지 않은 녀석의 경우, public 한 요소만 반환한다.

반면 Declared가 붙은 녀석은 private, protected 요소까지 모두 반환한다.

(둘 다 superclass까지 조사하는건 마찬가지)


초기에는 성능(속도) 문제때문에 많이 사용하지 않았다고 하는데,

최근의 JVM에서는 하드웨어의 속도향상과 더불어 크게 신경쓸정도는 아니라고 한다.


정규식과 더불어 variant한 코드 작성시 도움이 될듯 싶다.


And