'Language/JAVA'에 해당되는 글 57건

  1. 2016.08.04 java class loader #1 1
  2. 2016.08.04 [Java] ClassLoader API
  3. 2015.01.09 PropertyEditorRegistrySupport.java : private void createDefaultEditors()
  4. 2014.12.01 Java Reflection - Dynamic Class Loading and Reloading
  5. 2014.12.01 Java Reflection - Dynamic Proxies
  6. 2014.12.01 Java Reflection - Arrays
  7. 2014.12.01 Java Reflection - Generics
  8. 2014.12.01 Java Reflection - Annotations
  9. 2014.12.01 Java Reflection - Private Fields and Methods
  10. 2014.12.01 Java Reflection - Getters and Setters

java class loader #1

Language/JAVA 2016. 8. 4. 15:06

Java 동적으로 클래스를 로딩하기 때문에 런타임에 모든 코드가 JVM 링크됩니다모든 클래스는 해당 클래스가 참조되는 순간에 동적으로 JVM 링크되며메모리에 로딩됩니다자바의 런타임 라이브러리([jdk path]/jre/lib/rt.jar) 역시 예외가 아닙니다이러한 동적인클래스 로딩은 자바의 클래스로더 시스템을 통해서 이루어지며자바가 기본적으로 제공하는 클래스로더는 java.lang.ClassLoader 통해서 표현됩니다. JVM 시작되면부트스트랩(bootstrap) 클래스로더를 생성하고 다음에 가장 첫번째 클래스인 Object 시스템에 로딩합니다.
런타임에 동적으로 클래스를 로딩한다는 것은 JVM 클래스에 대한 정보를 갖고 있지 않다는 것을 의미함으로서 JVM 클래스에 대한정보를 알지 못합니다따라서클래스로더는 클래스를 로딩할  필요한 정보를 구하고 클래스가 올바른지를 검사해야 합니다.


Load-time dynamic loading and Run-time dynamic loading

클래스를 로딩하는 방식에는 로드타임 동적 로딩(load-time dynamic loading) 런타임 동적 로딩(run-time dynamic loading) 있습니다. 

  public class HelloWorld {
     public static void main(String[] args) {
        System.out.println("
안녕하세요!");
     }
  }

코드 1.


로드타임 동적 로딩은 하나의 클래스를 로딩하는 과정에서 동적으로 클래스를 로딩하는 것을 말합니다코드 1 HelloWorld 클래스를 실행하면, JVM 시작되고앞에서 말했듯이 부트스트랩 클래스로더가 생성된 후에모든 클래스가 상속받고 있는 Object 클래스를 읽어옵니다 이후에클래스로더는 명령행에서 지정한 HelloWorld 클래스를 로딩하기 위해 HelloWorld.class 파일을 읽습니다그리고HelloWorld 클래스를 로딩하는 과정에서 필요한 클래스 java.lang.String java.lang.System 읽어옵니다  클래스는 HelloWorld 클래스를 읽어오는 로드타임에 동적으로 로딩됩니다.

 

class HelloWorld1 implements Runnable {
     public void run() {
        System.out.println("
안녕하세요, 1");
     }
  }
  class HelloWorld2 implements Runnable {
     public void run() {
        System.out.println("
안녕하세요, 2");
     }
  }

  public class RuntimeLoading {
     public static void main(String[] args) {
        try {
           if (args.length < 1) {
              System.out.println("
사용법: java RuntimeLoading [클래스 이름]");
              System.exit(1);
           }
           Class klass = Class.forName(args[0]);
           Object obj = klass.newInstance();
           Runnable r = (Runnable) obj;
           r.run();
        } catch(Exception ex) {
           ex.printStackTrace();
        }
     }
  }

코드 2.

 

런타임 동적 로딩은 클래스를 로딩할 때가 아닌 코드를 실행하는 순간에 클래스를 로딩하는 것을 말합니다.


코드 2에서 Class.forName(className) 파리미터로 받은 className 해당하는 클래스를 로딩한 후에  클래스에 해당하는 로딩한 클래스의 인스턴스가 아닌 Class 인스턴스를 리턴합니다그리고 Class 클래스의 newInstance() 메소드는 Class 나타내는 클래스의 인스턴스를 생성합니다예를 들어코드 3 java.lang.String 클래스의 객체를 생성합니다.

  Class klass = Class.forName("java.lang.String");
  Object obj = klass.newInstance();

코드 3.


따라서, Class.forName() 메소드를 실행하는 클래스에서는 Class.forName() 실행되기 전까지는 어떤 클래스를 참조하는    없습니다.


ClassLoader

클래스로더를 사용하기 위해서는 보통의 자바 클래스처럼 해당하는 클래스의 객체를 생성하고 객체의 특정 메소드를 호출하면 됩니다또한상속을 받아 클래스로드를 커스터마이징  수도 있습니다.

자바의 클래스로더는 클래스로더 딜리게이션 모델(ClassLoader Delegation Model)으로서 부모 클래스로더가 먼저 클래스를 로딩하도록합니다특정 클래스로더 클래스를 읽어온 클래스로더(부모 클래스로더)에게 클래스 로딩을 요청하는 것입니다


그림 1. ClassLoader Delegation Model[1]


그림 1 클래스로더간의 관계를 보여주고 있습니다 경우, NetworkClassLoader(가정) JarFileClassLoader(가정) 로딩하고, JarFileClassLoader 클래스는 AppClassLoader 로딩하였음을 보여줍니다, JarFileClassLoader NetworkClassLoader 부모 클래스로더가 되고, AppClassLoader JarFileClassLoader 부모 클래스로더가 되는 것입니다.

<자바에서 기본으로 제공하는 부트스트랩클래스로더 등에 관한 설명은 [2-3] 보면   있습니다.>


References

 

[1] http://javacan.tistory.com/3

[2] http://blog.naver.com/PostView.nhn?blogId=choigohot&logNo=40192701035

[3] http://javacan.tistory.com/entry/2

 

:

[Java] ClassLoader API

Language/JAVA 2016. 8. 4. 14:59

http://java.sun.com/javase/6/docs/api/java/lang/ClassLoader.html


클래스를 로딩하는 책임을 지니고 있는 추상 클래스. 

기본전략: 바이너리 이름(String)을 받아서 파일 이름으로 바꾸고 파일 시스템에서 해당하는 이름의 클래스 파일을 읽어들인다.

위임 모델(delegation model)을 사용하여 클래스와 리소스를 찾는다. 각각의 ClassLoader 인스턴스는 연관된 상위(parent) 클래스 로더를 가지고 있다. 자신이 찾아 보기전에 상위 클래스 로더에 요청하여 먼저 찾아본다. VM 내장 클래스 로더인 "부트스트랩 클래스 로더"는 상위 클래스 로더가 없고 자신이 다른 ClassLoader 인스턴스의 상위가 된다.

보통 JVM은 플랫폼-독립적인 방식으로 로컬 파일 시스템에서 클래스를 읽어들인다. 예를 들어 유닉스 시스템에서 VM은 CLASSPATH 환경 변수에 정의되어 있는 디렉토리에서 클래스를 로딩한다.

하지만 어떤 클래스들은 파일에서 읽어오지 않고 네트워크에서 가져오거나 애플리케이션이 동작하면서 만들어지는 것도 있다. defineClass 메서드는 바이트 배열을 Class 클래스 인스턴스로 변환한다. Class.newInstance를 사용하여 그렇게 새로 정의된 클래스 인스턴스를 만들 수 있다.

클래스로더에 의해 만들어지는 객체의 메소드와 생성자는 다른 클래스를 참조할 수도 있다. 그렇게 참조하는 클래스들을 판단하기 위해 VM은 원래 클래스를 생성한 클래스 로더의 loadClass 메서드를 호출한다.

예를 들어 네트워크 클래스 로더를 만들어 다른 서버에서 클래스 파일을 다운로드 할 수도 있다. 다음은 예제 코드다.

ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();

네트워크 클래스 로더는 반드시 findClass와 네트워크에서 클래스를 읽어올 loadClassData를 정의해야한다. 바이트코드를 다운로드 한다음 defineClass를 사용하여 class 인스턴스를 만들어야 한다. 다음은 예제 구현체다.

     class NetworkClassLoader extends ClassLoader {
         String host;
         int port;

         public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }

         private byte[] loadClassData(String name) {
             // load the class data from the connection
              . . .
         }
     }
 

바이너리 이름

클래스로더에 전달되는 문자열로 표현한 클래스 이름은 다음에 정의된 자바 언어 표준을 따라야 한다.

예)
   "java.lang.String"
   "javax.swing.JSpinner$DefaultEditor"
   "java.security.KeyStore$Builder$FileBuilder$1"
   "java.net.URLClassLoader$3$1"

defineClass

- protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError

바이트를 Class 클래스의 인스턴스로 변환한다. Class는 resolve를 한 다음에 사용해야 한다. 

loadClass

- public Class<?> loadClass(String name) throws ClassNotFountException

loadClass(naem, false); 호출

- public Class<?> loadClass(String name, boolean resolve) throws ClassNotFountException

기본 동작은 다음과 같다.
1. findLoadedClass(String)을 호출하여 클래스가 이미 로딩되었는지 확인한다.
2. 상위 클래스 로더의 loadClass 메서드를 호출한다. 만약 상위 클래스 로더가 null이면 VM 내장 클래스 로더를 사용한다.
3. findClass(String) 메서드를 사용하여 클래스를 찾는다.

만약에 위 과정을 통해 클래스를 찾은 뒤에 resolve 플래그가 true면 반환받은 Class 객체를 사용하여resolveClass(Class) 메서드를 호출한다.

클래스로더의 하위 클래스들은 이 메서드가 아니라 findClass(String)을 재정의 할 것을 권한다.
(이런걸 지켜야 리스코프 원칙을 지켰다고 하던가...)

findLoadedClass

- protected final Class<?> findLoadedClass(String name)

만약 이 클래스로더가 JVM에 initiating 로더로 기록되어 있다면 name에 해당하는 클래스를 반환한다. 그렇지 않으면 null을 반환한다.

findClass

- protected Class<?> findClass(String name) throws ClassNotFoundException

기본 구현체는 ClassNotFoundException을 던진다. 따라서 클래스 로더를 확장하는 클래스가 이것을 구현하여 delegation 모델을 따르는 구현체를 만드는데 사용해야 한다. loadClass 메서드에서 상위 클래스 로더를 확인 한 뒤에 호출된다.
(그냥 클래스만 찾으면 되지 꼭 delegation 모델을 따라야 하는건가... 사실 loadClass가 public이라 그것도 재정의하면 그만인것을. 강요하려면 하고 말려면 말지 어중간한거 아닌가..)

resolveClass

- protected final void resolveClass(Class<?> c)

해당 클래스를 링크한다. 이 메서드는 클래스 로더가 클래스를 링크할 때 사용된다. 만약 클래스 c가 이미 링크되어 있다면 이 메서드는 그냥 끝난다. 그렇지 않은 경우라면 자바 언어 스팩의 "Execution" 챕터에 기술되어 있는대로 클래스를 링크한다.

링크


링크하기(Linking)란 클래스 또는 인터페이스 타입의 바이너리를 가져와서 JVM의 런타임에 연결하여 실행 할 수 있는 상태로 만드는 것이다. 

링크 과정은 세 가지 세부 활동으로 구성된다: verification, preparation, resolution

링크 활동 구현내용은 달라질 수 있다. 예를 들어 클래스가 사용되는 순간에 개별적으로 클래스나 인터페이스에 있는 심볼릭 레퍼런스를 확정하거나(lazy or late resolution), 검증하고나서 바로 확정할 수도 있다.(static). 즉 어떤 구현체에서는 클래스나 인터페이스를 초기화 한 이후에도 확정(resolution) 프로세스가 계속 될 수 있다는 것이다.

Verification, Preparation, Resolution


Verification: 클래스나 인터페이스의 바이너리가 구조적으로 올바른지 확인한다. 검증에 실패하면LinkageError의 하위 클래스 중 하나인 VerifyError가 발생한다.

Preparation: 클래스나 인터페이스의 static 필드를 만들고 그런 필드들을 기본 값으로 초기화 하는 과정이 포함된다. 이 과정 중에 JVM 코드를 실행할 필요가 없다. 명시적인 static 필드 initializer는 이 과정이 아니라 initialization 과정에서 실행된다.

Resolution: 심볼릭 레퍼런스는 resolution단계를 지나야지 사용될 수 있다. 심볼릭 레퍼런스가 유효하고 반복적으로 사용되면 다이렉트 레퍼런스로 교체되어 보다 효율적으로 처리된다.

만약 이 단계를 지나다가 IncompatibleClassChangeError를 포함한 이 하위 에러들이 발생할 수 있다. IllegalAccessErrorInstantiationErrorNoSuchFieldErrorNoSuchMethodError

추가적으로 구현체를 찾을 수 없는 native 메서드를 선언한 클래스에서는 UnsatisfiedLinkError가 발생할 수 있다. 


출처 - http://whiteship.tistory.com/2560

:

PropertyEditorRegistrySupport.java : private void createDefaultEditors()

Language/JAVA 2015. 1. 9. 14:45

private void createDefaultEditors() { this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64); // Simple editors, without parameterization capabilities. // The JDK does not contain a default editor for any of these target types. this.defaultEditors.put(Charset.class, new CharsetEditor()); this.defaultEditors.put(Class.class, new ClassEditor()); this.defaultEditors.put(Class[].class, new ClassArrayEditor()); this.defaultEditors.put(Currency.class, new CurrencyEditor()); this.defaultEditors.put(File.class, new FileEditor()); this.defaultEditors.put(InputStream.class, new InputStreamEditor()); this.defaultEditors.put(InputSource.class, new InputSourceEditor()); this.defaultEditors.put(Locale.class, new LocaleEditor()); this.defaultEditors.put(Pattern.class, new PatternEditor()); this.defaultEditors.put(Properties.class, new PropertiesEditor()); this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor()); this.defaultEditors.put(TimeZone.class, new TimeZoneEditor()); this.defaultEditors.put(URI.class, new URIEditor()); this.defaultEditors.put(URL.class, new URLEditor()); this.defaultEditors.put(UUID.class, new UUIDEditor()); // Default instances of collection editors. // Can be overridden by registering custom instances of those as custom editors. this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class)); this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class)); this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class)); this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class)); this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class)); // Default editors for primitive arrays. this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor()); this.defaultEditors.put(char[].class, new CharArrayPropertyEditor()); // The JDK does not contain a default editor for char! this.defaultEditors.put(char.class, new CharacterEditor(false)); this.defaultEditors.put(Character.class, new CharacterEditor(true)); // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor. this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false)); this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true)); // The JDK does not contain default editors for number wrapper types! // Override JDK primitive number editors with our own CustomNumberEditor. this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false)); this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true)); this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false)); this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true)); this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false)); this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true)); this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false)); this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true)); this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false)); this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true)); this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false)); this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true)); this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true)); this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true)); // Only register config value editors if explicitly requested. if (this.configValueEditorsActive) { StringArrayPropertyEditor sae = new StringArrayPropertyEditor(); this.defaultEditors.put(String[].class, sae); this.defaultEditors.put(short[].class, sae); this.defaultEditors.put(int[].class, sae); this.defaultEditors.put(long[].class, sae); } }




응용 



package net.slipp.web; import java.beans.PropertyEditor; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.propertyeditors.CustomBooleanEditor; import org.springframework.beans.propertyeditors.CustomNumberEditor; import org.springframework.mock.web.MockHttpServletRequest; public class ReflectionTest { private static Logger log = LoggerFactory.getLogger(ReflectionTest.class); @SuppressWarnings("serial") private static Map<Class<?>, PropertyEditor> defaultEditors = new HashMap<Class<?>, PropertyEditor>() { { put(boolean.class, new CustomBooleanEditor(false)); put(Boolean.class, new CustomBooleanEditor(true)); put(byte.class, new CustomNumberEditor(Byte.class, false)); put(Byte.class, new CustomNumberEditor(Byte.class, true)); put(int.class, new CustomNumberEditor(Integer.class, false)); put(Integer.class, new CustomNumberEditor(Integer.class, true)); put(long.class, new CustomNumberEditor(Long.class, false)); put(Long.class, new CustomNumberEditor(Long.class, true)); } }; @Test public void populateFromRequestToUser() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter("userId", "test"); request.addParameter("name", "슬립"); request.addParameter("userNo", "12356"); request.addParameter("age", "35"); MockUser user = new MockUser(); Field[] fields = MockUser.class.getDeclaredFields(); for (Field field : fields) { log.debug("field name : {}", field.getName()); field.setAccessible(true); String value = request.getParameter(field.getName()); if (field.getType() == String.class) { field.set(user, value); continue; } PropertyEditor propertyEditor = defaultEditors.get(field.getType()); if (propertyEditor != null) { propertyEditor.setAsText(value); field.set(user, propertyEditor.getValue()); } } log.debug("User : {}", user); } private class MockUser { private long userNo; private Integer age; private String userId; private String name; @Override public String toString() { return "MockUser [userNo=" + userNo + ", age=" + age + ", userId=" + userId + ", name=" + name + "]"; } } }



출처 http://slipp.net/questions/85


'Language > JAVA' 카테고리의 다른 글

java class loader #1  (1) 2016.08.04
[Java] ClassLoader API  (0) 2016.08.04
Java Reflection - Dynamic Class Loading and Reloading  (0) 2014.12.01
Java Reflection - Dynamic Proxies  (0) 2014.12.01
Java Reflection - Arrays  (0) 2014.12.01
:

Java Reflection - Dynamic Class Loading and Reloading

Language/JAVA 2014. 12. 1. 11:43

It is possible to load and reload classes at runtime in Java, though it is not as straightforward as one might have hoped. This text will explain when and how you can load and reload classes in Java.

You can argue whether Java's dynamic class loading features are really part of Java Reflection, or a part of the core Java platform. Anyways, the article has been put in the Java Reflection trail in lack of a better place to put it.

The ClassLoader

All classes in a Java application are loaded using some subclass of java.lang.ClassLoader. Loading classes dynamically must therefore also be done using a java.lang.ClassLoader subclass.

When a class is loaded, all classes it references are loaded too. This class loading pattern happens recursively, until all classes needed are loaded. This may not be all classes in the application. Unreferenced classes are not loaded until the time they are referenced.

The ClassLoader Hierarchy

Class loaders in Java are organized into a hierarchy. When you create a new standard Java ClassLoader you must provide it with a parent ClassLoader. If a ClassLoader is asked to load a class, it will ask its parent class loader to load it. If the parent class loader can't find the class, the child class loader then tries to load it itself.

Class Loading

The steps a given class loader uses when loading classes are:

  1. Check if the class was already loaded.
  2. If not loaded, ask parent class loader to load the class.
  3. If parent class loader cannot load class, attempt to load it in this class loader.

When you implement a class loader that is capable of reloading classes you will need to deviate a bit from this sequence. The classes to reload should not be requested loaded by the parent class loader. More on that later.

Dynamic Class Loading

Loading a class dynamically is easy. All you need to do is to obtain a ClassLoader and call its loadClass()method. Here is an example:

public class MainClass {

  public static void main(String[] args){

    ClassLoader classLoader = MainClass.class.getClassLoader();

    try {
        Class aClass = classLoader.loadClass("com.jenkov.MyClass");
        System.out.println("aClass.getName() = " + aClass.getName());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}

Dynamic Class Reloading

Dynamic class reloading is a bit more challenging. Java's builtin Class loaders always checks if a class is already loaded before loading it. Reloading the class is therefore not possible using Java's builtin class loaders. To reload a class you will have to implement your own ClassLoader subclass.

Even with a custom subclass of ClassLoader you have a challenge. Every loaded class needs to be linked. This is done using the ClassLoader.resolve() method. This method is final, and thus cannot be overridden in yourClassLoader subclass. The resolve() method will not allow any given ClassLoader instance to link the same class twice. Therefore, everytime you want to reload a class you must use a new instance of your ClassLoadersubclass. This is not impossible, but necessary to know when designing for class reloading.

Designing your Code for Class Reloading

As stated earlier you cannot reload a class using a ClassLoader that has already loaded that class once. Therefore you will have to reload the class using a different ClassLoader instance. But this poses som new challenges.

Every class loaded in a Java application is identified by its fully qualified name (package name + class name), and theClassLoader instance that loaded it. That means, that a class MyObject loaded by class loader A, is not the same class as the MyObject class loaded with class loader B. Look at this code:

MyObject object = (MyObject)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

Notice how the MyObject class is referenced in the code, as the type of the object variable. This causes theMyObject class to be loaded by the same class loader that loaded the class this code is residing in.

If the myClassReloadingFactory object factory reloads the MyObject class using a different class loader than the class the above code resides in, you cannot cast the instance of the reloaded MyObject class to the MyObject type of the object variable. Since the two MyObject classes were loaded with different class loaders, the are regarded as different classes, even if they have the same fully qualified class name. Trying to cast an object of the one class to a reference of the other will result in a ClassCastException.

It is possible to work around this limitation but you will have to change your code in either of two ways:

  1. Use an interface as the variable type, and just reload the implementing class.
  2. Use a superclass as the variable type, and just reload a subclass.

Here are two coresponding code examples:

MyObjectInterface object = (MyObjectInterface)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");
MyObjectSuperclass object = (MyObjectSuperclass)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

Either of these two methods will work if the type of the variable, the interface or superclass, is not reloaded when the implementing class or subclass is reloaded.

To make this work you will of course need to implement your class loader to let the interface or superclass be loaded by its parent. When your class loader is asked to load the MyObject class, it will also be asked to load theMyObjectInterface class, or the MyObjectSuperclass class, since these are referenced from within theMyObject class. Your class loader must delegate the loading of those classes to the same class loader that loaded the class containing the interface or superclass typed variables.

ClassLoader Load / Reload Example

The text above has contained a lot of talk. Let's look at a simple example. Below is an example of a simpleClassLoader subclass. Notice how it delegates class loading to its parent except for the one class it is intended to be able to reload. If the loading of this class is delegated to the parent class loader, it cannot be reloaded later. Remember, a class can only be loaded once by the same ClassLoader instance.

As said earlier, this is just an example that serves to show you the basics of a ClassLoader's behaviour. It is not a production ready template for your own class loaders. Your own class loaders should probably not be limited to a single class, but a collection of classes that you know you will need to reload. In addition, you should probably not hardcode the class paths either.

public class MyClassLoader extends ClassLoader{

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    public Class loadClass(String name) throws ClassNotFoundException {
        if(!"reflection.MyObject".equals(name))
                return super.loadClass(name);

        try {
            String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +
                            "classes/reflection/MyObject.class";
            URL myUrl = new URL(url);
            URLConnection connection = myUrl.openConnection();
            InputStream input = connection.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();

            while(data != -1){
                buffer.write(data);
                data = input.read();
            }

            input.close();

            byte[] classData = buffer.toByteArray();

            return defineClass("reflection.MyObject",
                    classData, 0, classData.length);

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}


Below is an example use of the MyClassLoader.

public static void main(String[] args) throws
    ClassNotFoundException,
    IllegalAccessException,
    InstantiationException {

    ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
    MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
    Class myObjectClass = classLoader.loadClass("reflection.MyObject");

    AnInterface2       object1 =
            (AnInterface2) myObjectClass.newInstance();

    MyObjectSuperClass object2 =
            (MyObjectSuperClass) myObjectClass.newInstance();

    //create new class loader so classes can be reloaded.
    classLoader = new MyClassLoader(parentClassLoader);
    myObjectClass = classLoader.loadClass("reflection.MyObject");

    object1 = (AnInterface2)       myObjectClass.newInstance();
    object2 = (MyObjectSuperClass) myObjectClass.newInstance();

}


Here is the reflection.MyObject class that is loaded using the class loader. Notice how it both extends a superclass and implements an interface. This is just for the sake of the example. In your own code you would only have to one of the two - extend or implement.

public class MyObject extends MyObjectSuperClass implements AnInterface2{
    //... body of class ... override superclass methods
    //    or implement interface methods
}

출처 - http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html


'Language > JAVA' 카테고리의 다른 글

[Java] ClassLoader API  (0) 2016.08.04
PropertyEditorRegistrySupport.java : private void createDefaultEditors()  (0) 2015.01.09
Java Reflection - Dynamic Proxies  (0) 2014.12.01
Java Reflection - Arrays  (0) 2014.12.01
Java Reflection - Generics  (0) 2014.12.01
:

Java Reflection - Dynamic Proxies

Language/JAVA 2014. 12. 1. 11:43

Using Java Reflection you create dynamic implementations of interfaces at runtime. You do so using the classjava.lang.reflect.Proxy. The name of this class is why I refer to these dynamic interface implementations as dynamic proxies. Dynamic proxies can be used for many different purposes, e.g. database connection and transaction management, dynamic mock objects for unit testing, and other AOP-like method intercepting purposes.

Creating Proxies

You create dynamic proxies using the Proxy.newProxyInstance() method. The newProxyInstance() methods takes 3 parameters:

  1. The ClassLoader that is to "load" the dynamic proxy class.
  2. An array of interfaces to implement.
  3. An InvocationHandler to forward all methods calls on the proxy to.

Here is an example:

InvocationHandler handler = new MyInvocationHandler();
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                            MyInterface.class.getClassLoader(),
                            new Class[] { MyInterface.class },
                            handler);

After running this code the proxy variable contains a dynamic implementation of the MyInterface interface. All calls to the proxy will be forwarded to the handler implementation of the general InvocationHandler interface. InvocationHandler's are covered i the next section.

InvocationHandler's

As mentioned earlier you must pass an InvocationHandler implementation to the Proxy.newProxyInstance()method. All method calls to the dynamic proxy are forwarded to this InvocationHandler implementation. Here is how the InvocationHandler interface looks:

public interface InvocationHandler{
  Object invoke(Object proxy, Method method, Object[] args)
         throws Throwable;
}

Here is an example implementation:

public class MyInvocationHandler implements InvocationHandler{

  public Object invoke(Object proxy, Method method, Object[] args)
  throws Throwable {
    //do something "dynamic"
  }
}

The proxy parameter passed to the invoke() method is the dynamic proxy object implementing the interface. Most often you don't need this object.

The Method object passed into the invoke() method represents the method called on the interface the dynamic proxy implements. From the Method object you can obtain the method name, parameter types, return type, etc. See the text on Methods for more information.

The Object[] args array contains the parameter values passed to the proxy when the method in the interface implemented was called. Note: Primitives (int, long etc) in the implemented interface are wrapped in their object counterparts (Integer, Long etc.).

Known Use Cases

Dynamic proxies are known to be used for at least the following purposes:

  • Database Connection and Transaction Management
  • Dynamic Mock Objects for Unit Testing
  • Adaptation of DI Container to Custom Factory Interfaces
  • AOP-like Method Interception

Database Connection and Transaction Management

The Spring framework has a transaction proxy that can start and commit / rollback a transaction for you. How this works is described in more detail in the text Advanced Connection and Transaction Demarcation and Propagation , so I'll only describe it briefly. The call sequence becomes something along this:

web controller --> proxy.execute(...);
  proxy --> connection.setAutoCommit(false);
  proxy --> realAction.execute();
    realAction does database work
  proxy --> connection.commit();

Dynamic Mock Objects for Unit Testing

The Butterfly Testing Tools makes use of dynamic proxies to implement dynamic stubs, mocks and proxies for unit testing. When testing a class A that uses another class B (interface really), you can pass a mock implementation of B into A instead of a real B. All method calls on B are now recorded, and you can set what return values the mock B is to return.

Furthermore Butterfly Testing Tools allow you to wrap a real B in a mock B, so that all method calls on the mock are recorded, and then forwarded to the real B. This makes it possible to check what methods were called on a real functioning B. For instance, if testing a DAO you can wrap the database connection in a mock. The DAO will not see the difference, and the DAO can read/write data to the database as usual since the mock forwards all calls to the database. But now you can check via the mock if the DAO uses the connection properly, for instance if theconnection.close() is called (or NOT called), if you expected that. This is normally not possible to determine from the return value of a DAO.

Adaptation of DI Container to Custom Factory Interfaces

The dependency injection container Butterfly Container has a powerful feature that allows you to inject the whole container into beans produced by it. But, since you don't want a dependency on the container interface, the container is capable of adapting itself to a custom factory interface of your design. You only need the interface. No implementation. Thus the factory interface and your class could look something like this:

public interface IMyFactory {
  Bean   bean1();
  Person person();
  ...
}
public class MyAction{

  protected IMyFactory myFactory= null;

  public MyAction(IMyFactory factory){
    this.myFactory = factory;
  }

  public void execute(){
    Bean bean = this.myFactory.bean();
    Person person = this.myFactory.person();
  }

}

When the MyAction class calls methods on the IMyFactory instance injected into its constructor by the container, the method calls are translated into calls to the IContainer.instance() method, which is the method you use to obtain instances from the container. That way an object can use Butterfly Container as a factory at runtime, rather than only to have dependencies injected into itself at creation time. And this without having any dependencies on any Butterfly Container specific interfaces.

AOP-like Method Interception

The Spring framework makes it possible to intercept method calls to a given bean, provided that bean implements some interface. The Spring framework wraps the bean in a dynamic proxy. All calls to the bean are then intercepted by the proxy. The proxy can decide to call other methods on other objects either before, instead of, or after delegating the method call to the bean wrapped.


출처 - http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html


:

Java Reflection - Arrays

Language/JAVA 2014. 12. 1. 11:42

Working with arrays in Java Reflection can be a bit tricky at times. Especially if you need to obtain the Class object for a certain type of array, like int[] etc. This text will discuss how to both create arrays and get their class objects via Java Reflection.

Note: This text has been updated after reading Eyal Lupu's blog post 
"Two Side Notes About Arrays and Reflection" which commented on the first edition of this text. The current edition takes his comments into consideration.

java.lang.reflect.Array

Working with arrays via Java Reflection is done using the java.lang.reflect.Array class. Do not confuse this class with the java.util.Arrays class in the Java Collections suite, which contains utility methods for sorting arrays, converting them to collections etc.

Creating Arrays

Creating arrays via Java Reflection is done using the java.lang.reflect.Array class. Here is an example showing how to create an array:

int[] intArray = (int[]) Array.newInstance(int.class, 3);

This code sample creates an array of int. The first parameter int.class given to the Array.newInstance()method tells what type each element in the array should be of. The second parameter states how many elements the array should have space for.

Accessing Arrays

It is also possible to access the elements of an array using Java Reflection. This is done via the Array.get(...)and Array.set(...) methods. Here is an example:

int[] intArray = (int[]) Array.newInstance(int.class, 3);

Array.set(intArray, 0, 123);
Array.set(intArray, 1, 456);
Array.set(intArray, 2, 789);

System.out.println("intArray[0] = " + Array.get(intArray, 0));
System.out.println("intArray[1] = " + Array.get(intArray, 1));
System.out.println("intArray[2] = " + Array.get(intArray, 2));

This code sample will print out this:

intArray[0] = 123
intArray[1] = 456
intArray[2] = 789

Obtaining the Class Object of an Array

One of the problems I ran into when implementing the script language in Butterfly DI Container was how to obtain theClass object for arrays via Java Reflection. Using non-reflection code you can do like this:

Class stringArrayClass = String[].class;

Doing this using Class.forName() is not quite straightforward. For instance, you can access the primitive int array class object like this:

Class intArray = Class.forName("[I");

The JVM represents an int via the letter I. The [ on the left means it is the class of an int array I am interested in. This works for all other primitives too.

For objects you need to use a slightly different notation:

Class stringArrayClass = Class.forName("[Ljava.lang.String;");

Notice the [L to the left of the class name, and the ; to the right. This means an array of objects with the given type.

As a side note, you cannot obtain the class object of primitives using Class.forName(). Both of the examples below result in a ClassNotFoundException:

Class intClass1 = Class.forName("I");
Class intClass2 = Class.forName("int");

I usually do something like this to obtain the class name for primitives as well as objects:

public Class getClass(String className){
  if("int" .equals(className)) return int .class;
  if("long".equals(className)) return long.class;
  ...
  return Class.forName(className);
}

Once you have obtained the Class object of a type there is a simple way to obtain the Class of an array of that type. The solution, or workaround as you might call it, is to create an empty array of the desired type and obtain the class object from that empty array. It's a bit of a cheat, but it works. Here is how that looks:

Class theClass = getClass(theClassName);
Class stringArrayClass = Array.newInstance(theClass, 0).getClass();

This presents a single, uniform method to access the array class of arrays of any type. No fiddling with class names etc.

To make sure that the Class object really is an array, you can call the Class.isArray() method to check:

Class stringArrayClass = Array.newInstance(String.class, 0).getClass();
System.out.println("is array: " + stringArrayClass.isArray());

Obtaining the Component Type of an Array

Once you have obtained the Class object for an array you can access its component type via theClass.getComponentType() method. The component type is the type of the items in the array. For instance, the component type of an int[] array is the int.class Class object. The component type of a String[] array is thejava.lang.String Class object.

Here is an example of accessing the component type array:

String[] strings = new String[3];
Class stringArrayClass = strings.getClass();
Class stringArrayComponentType = stringArrayClass.getComponentType();
System.out.println(stringArrayComponentType);

This example will print out the text "java.lang.String" which is the component type of the String array.


출처 - http://tutorials.jenkov.com/java-reflection/arrays.html


:

Java Reflection - Generics

Language/JAVA 2014. 12. 1. 11:42

I have often read in articles and forums that all Java Generics information is erased at compile time so that you cannot access any of that information at runtime. This is not entirely true though. It is possible to access generics information at runtime in a handful of cases. These cases actually cover several of our needs for Java Generics information. This text explains these cases.

The Generics Reflection Rule of Thumb

Using Java Generics typically falls into one of two different situations:

  1. Declaring a class/interface as being parameterizable.
  2. Using a parameterizable class.

When you write a class or interface you can specify that it should be paramerizable. This is the case with thejava.util.List interface. Rather than create a list of Object you can parameterize java.util.List to create a list of say String.

When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in the same application. But, when you inspect the method or field that declares the use of a parameterized type, you can see at runtime what type the paramerizable type was parameterized to. In short:

You cannot see on a type itself what type it is parameterized to a runtime, but you can see it in fields and methods where it is used and parameterized. Its concrete parameterizations in other words.

The following sections take a closer look at these situations.

Generic Method Return Types

If you have obtained a java.lang.reflect.Method object it is possible to obtain information about its generic return type. This cannot be any of the Method objects in the parameterized type, but in the class that uses the parameterized type. You can read how to obtain Method objects in the text "Java Generics: Methods". Here is an example class with a method having a parameterized return type:

public class MyClass {

  protected List<String> stringList = ...;

  public List<String> getStringList(){
    return this.stringList;
  }
}

In this class it is possible to obtain the generic return type of the getStringList() method. In other words, it is possible to detect that getStringList() returns a List<String> and not just a List. Here is how:

Method method = MyClass.class.getMethod("getStringList", null);

Type returnType = method.getGenericReturnType();

if(returnType instanceof ParameterizedType){
    ParameterizedType type = (ParameterizedType) returnType;
    Type[] typeArguments = type.getActualTypeArguments();
    for(Type typeArgument : typeArguments){
        Class typeArgClass = (Class) typeArgument;
        System.out.println("typeArgClass = " + typeArgClass);
    }
}

This piece of code will print out the text "typeArgClass = java.lang.String". The Type[] array typeArguments array will contain one item - a Class instance representing the class java.lang.StringClass implements the Typeinterface.

Generic Method Parameter Types

You can also access the generic types of parameter types at runtime via Java Reflection. Here is an example class with a method taking a parameterized List as parameter:

public class MyClass {
  protected List<String> stringList = ...;

  public void setStringList(List<String> list){
    this.stringList = list;
  }
}

You can access the generic parameter types of the method parameters like this:

method = Myclass.class.getMethod("setStringList", List.class);

Type[] genericParameterTypes = method.getGenericParameterTypes();

for(Type genericParameterType : genericParameterTypes){
    if(genericParameterType instanceof ParameterizedType){
        ParameterizedType aType = (ParameterizedType) genericParameterType;
        Type[] parameterArgTypes = aType.getActualTypeArguments();
        for(Type parameterArgType : parameterArgTypes){
            Class parameterArgClass = (Class) parameterArgType;
            System.out.println("parameterArgClass = " + parameterArgClass);
        }
    }
}

This code will print out the text "parameterArgType = java.lang.String". The Type[] array parameterArgTypes array will contain one item - a Class instance representing the class java.lang.StringClass implements the Typeinterface.

Generic Field Types

It is also possible to access the generic types of public fields. Fields are class member variables - either static or instance variables. You can read about obtaining Field objects in the text "Java Generics: Fields". Here is the example from earlier, with an instance field called stringList.

public class MyClass {
  public List<String> stringList = ...;
}
Field field = MyClass.class.getField("stringList");

Type genericFieldType = field.getGenericType();

if(genericFieldType instanceof ParameterizedType){
    ParameterizedType aType = (ParameterizedType) genericFieldType;
    Type[] fieldArgTypes = aType.getActualTypeArguments();
    for(Type fieldArgType : fieldArgTypes){
        Class fieldArgClass = (Class) fieldArgType;
        System.out.println("fieldArgClass = " + fieldArgClass);
    }
}

This code will print out the text "fieldArgClass = java.lang.String". The Type[] array fieldArgTypes array will contain one item - a Class instance representing the class java.lang.StringClass implements the Typeinterface.


출처 - http://tutorials.jenkov.com/java-reflection/generics.html

'Language > JAVA' 카테고리의 다른 글

Java Reflection - Dynamic Proxies  (0) 2014.12.01
Java Reflection - Arrays  (0) 2014.12.01
Java Reflection - Annotations  (0) 2014.12.01
Java Reflection - Private Fields and Methods  (0) 2014.12.01
Java Reflection - Getters and Setters  (0) 2014.12.01
:

Java Reflection - Annotations

Language/JAVA 2014. 12. 1. 11:41

Using Java Reflection you can access the annotations attached to Java classes at runtime.

What are Java Annotations?

Annotations is a new feature from Java 5. Annotations are a kind of comment or meta data you can insert in your Java code. These annotations can then be processed at compile time by pre-compiler tools, or at runtime via Java Reflection. Here is an example of class annotation:

@MyAnnotation(name="someName",  value = "Hello World")
public class TheClass {
}

The class TheClass has the annotation @MyAnnotation written ontop. Annotations are defined like interfaces. Here is the MyAnnotation definition:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)

public @interface MyAnnotation {
    public String name();
    public String value();
}

The @ in front of the interface marks it as an annotation. Once you have defined the annotation you can use it in your code, as shown in the earlier examples.

The two directives in the annotation definition, @Retention(RetentionPolicy.RUNTIME) and@Target(ElementType.TYPE), specifies how the annotation is to be used.

@Retention(RetentionPolicy.RUNTIME) means that the annotation can be accessed via reflection at runtime. If you do not set this directive, the annotation will not be preserved at runtime, and thus not available via reflection.

@Target(ElementType.TYPE) means that the annotation can only be used ontop of types (classes and interfaces typically). You can also specify METHOD or FIELD, or you can leave the target out alltogether so the annotation can be used for both classes, methods and fields.

Java annotations are explained in more detail in my Java Annotations tutorial.

Class Annotations

You can access the annotations of a class, method or field at runtime. Here is an example that accesses the class annotations:

Class aClass = TheClass.class;
Annotation[] annotations = aClass.getAnnotations();

for(Annotation annotation : annotations){
    if(annotation instanceof MyAnnotation){
        MyAnnotation myAnnotation = (MyAnnotation) annotation;
        System.out.println("name: " + myAnnotation.name());
        System.out.println("value: " + myAnnotation.value());
    }
}

You can also access a specific class annotation like this:

Class aClass = TheClass.class;
Annotation annotation = aClass.getAnnotation(MyAnnotation.class);

if(annotation instanceof MyAnnotation){
    MyAnnotation myAnnotation = (MyAnnotation) annotation;
    System.out.println("name: " + myAnnotation.name());
    System.out.println("value: " + myAnnotation.value());
}

Method Annotations

Here is an example of a method with annotations:

public class TheClass {
  @MyAnnotation(name="someName",  value = "Hello World")
  public void doSomething(){}
}

You can access method annotations like this:

Method method = ... //obtain method object
Annotation[] annotations = method.getDeclaredAnnotations();

for(Annotation annotation : annotations){
    if(annotation instanceof MyAnnotation){
        MyAnnotation myAnnotation = (MyAnnotation) annotation;
        System.out.println("name: " + myAnnotation.name());
        System.out.println("value: " + myAnnotation.value());
    }
}

You can also access a specific method annotation like this:

Method method = ... // obtain method object
Annotation annotation = method.getAnnotation(MyAnnotation.class);

if(annotation instanceof MyAnnotation){
    MyAnnotation myAnnotation = (MyAnnotation) annotation;
    System.out.println("name: " + myAnnotation.name());
    System.out.println("value: " + myAnnotation.value());
}

Parameter Annotations

It is possible to add annotations to method parameter declarations too. Here is how that looks:

public class TheClass {
  public static void doSomethingElse(
        @MyAnnotation(name="aName", value="aValue") String parameter){
  }
}

You can access parameter annotations from the Method object like this:

Method method = ... //obtain method object
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Class[] parameterTypes = method.getParameterTypes();

int i=0;
for(Annotation[] annotations : parameterAnnotations){
  Class parameterType = parameterTypes[i++];

  for(Annotation annotation : annotations){
    if(annotation instanceof MyAnnotation){
        MyAnnotation myAnnotation = (MyAnnotation) annotation;
        System.out.println("param: " + parameterType.getName());
        System.out.println("name : " + myAnnotation.name());
        System.out.println("value: " + myAnnotation.value());
    }
  }
}

Notice how the Method.getParameterAnnotations() method returns a two-dimensional Annotation array, containing an array of annotations for each method parameter.

Field Annotations

Here is an example of a field with annotations:

public class TheClass {

  @MyAnnotation(name="someName",  value = "Hello World")
  public String myField = null;
}

You can access field annotations like this:

Field field = ... //obtain field object
Annotation[] annotations = field.getDeclaredAnnotations();

for(Annotation annotation : annotations){
    if(annotation instanceof MyAnnotation){
        MyAnnotation myAnnotation = (MyAnnotation) annotation;
        System.out.println("name: " + myAnnotation.name());
        System.out.println("value: " + myAnnotation.value());
    }
}

You can also access a specific field annotation like this:

Field field = ... // obtain method object
Annotation annotation = field.getAnnotation(MyAnnotation.class);

if(annotation instanceof MyAnnotation){
    MyAnnotation myAnnotation = (MyAnnotation) annotation;
    System.out.println("name: " + myAnnotation.name());
    System.out.println("value: " + myAnnotation.value());
}

출처 - http://tutorials.jenkov.com/java-reflection/annotations.html


'Language > JAVA' 카테고리의 다른 글

Java Reflection - Arrays  (0) 2014.12.01
Java Reflection - Generics  (0) 2014.12.01
Java Reflection - Private Fields and Methods  (0) 2014.12.01
Java Reflection - Getters and Setters  (0) 2014.12.01
Java Reflection - Methods  (0) 2014.12.01
:

Java Reflection - Private Fields and Methods

Language/JAVA 2014. 12. 1. 11:41

Despite the common belief it is actually possible to access private fields and methods of other classes via Java Reflection. It is not even that difficult. This can be very handy during unit testing. This text will show you how.

Note: This only works when running the code as a standalone Java application, like you do with unit tests and regular applications. If you try to do this inside a Java Applet, you will need to fiddle around with the SecurityManager. But, since that is not something you need to do very often, it is left out of this text so far.

Accessing Private Fields

To access a private field you will need to call the Class.getDeclaredField(String name) orClass.getDeclaredFields() method. The methods Class.getField(String name) andClass.getFields() methods only return public fields, so they won't work. Here is a simple example of a class with a private field, and below that the code to access that field via Java Reflection:

public class PrivateObject {

  private String privateString = null;

  public PrivateObject(String privateString) {
    this.privateString = privateString;
  }
}
PrivateObject privateObject = new PrivateObject("The Private Value");

Field privateStringField = PrivateObject.class.
            getDeclaredField("privateString");

privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue);

This code example will print out the text "fieldValue = The Private Value", which is the value of the private fieldprivateString of the PrivateObject instance created at the beginning of the code sample.

Notice the use of the method PrivateObject.class.getDeclaredField("privateString"). It is this method call that returns the private field. This method only returns fields declared in that particular class, not fields declared in any superclasses.

Notice the line in bold too. By calling Field.setAcessible(true) you turn off the access checks for this particularField instance, for reflection only. Now you can access it even if it is private, protected or package scope, even if the caller is not part of those scopes. You still can't access the field using normal code. The compiler won't allow it.

Accessing Private Methods

To access a private method you will need to call the Class.getDeclaredMethod(String name, Class[] parameterTypes) or Class.getDeclaredMethods() method. The methods Class.getMethod(String name, Class[] parameterTypes) and Class.getMethods() methods only return public methods, so they won't work. Here is a simple example of a class with a private method, and below that the code to access that method via Java Reflection:

public class PrivateObject {

  private String privateString = null;

  public PrivateObject(String privateString) {
    this.privateString = privateString;
  }

  private String getPrivateString(){
    return this.privateString;
  }
}
PrivateObject privateObject = new PrivateObject("The Private Value");

Method privateStringMethod = PrivateObject.class.
        getDeclaredMethod("getPrivateString", null);

privateStringMethod.setAccessible(true);

String returnValue = (String)
        privateStringMethod.invoke(privateObject, null);

System.out.println("returnValue = " + returnValue);

This code example will print out the text "returnValue = The Private Value", which is the value returned by the methodgetPrivateString() when invoked on the PrivateObject instance created at the beginning of the code sample.

Notice the use of the method PrivateObject.class.getDeclaredMethod("privateString"). It is this method call that returns the private method. This method only returns methods declared in that particular class, not methods declared in any superclasses.

Notice the line in bold too. By calling Method.setAcessible(true) you turn off the access checks for this particularMethod instance, for reflection only. Now you can access it even if it is private, protected or package scope, even if the caller is not part of those scopes. You still can't access the method using normal code. The compiler won't allow it.


출처 - http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html


'Language > JAVA' 카테고리의 다른 글

Java Reflection - Generics  (0) 2014.12.01
Java Reflection - Annotations  (0) 2014.12.01
Java Reflection - Getters and Setters  (0) 2014.12.01
Java Reflection - Methods  (0) 2014.12.01
Java Reflection - Fields  (0) 2014.12.01
:

Java Reflection - Getters and Setters

Language/JAVA 2014. 12. 1. 11:40

Using Java Reflection you can inspect the methods of classes and invoke them at runtime. This can be used to detect what getters and setters a given class has. You cannot ask for getters and setters explicitly, so you will have to scan through all the methods of a class and check if each method is a getter or setter.

First let's establish the rules that characterizes getters and setters:

  • Getter
    A getter method have its name start with "get", take 0 parameters, and returns a value. 

  • Setter
    A setter method have its name start with "set", and takes 1 parameter.

Setters may or may not return a value. Some setters return void, some the value set, others the object the setter were called on for use in method chaining. Therefore you should make no assumptions about the return type of a setter.

Here is a code example that finds getter and setters of a class:

public static void printGettersSetters(Class aClass){
  Method[] methods = aClass.getMethods();

  for(Method method : methods){
    if(isGetter(method)) System.out.println("getter: " + method);
    if(isSetter(method)) System.out.println("setter: " + method);
  }
}

public static boolean isGetter(Method method){
  if(!method.getName().startsWith("get"))      return false;
  if(method.getParameterTypes().length != 0)   return false;  
  if(void.class.equals(method.getReturnType()) return false;
  return true;
}

public static boolean isSetter(Method method){
  if(!method.getName().startsWith("set")) return false;
  if(method.getParameterTypes().length != 1) return false;
  return true;
}

출처 - http://tutorials.jenkov.com/java-reflection/getters-setters.html


'Language > JAVA' 카테고리의 다른 글

Java Reflection - Annotations  (0) 2014.12.01
Java Reflection - Private Fields and Methods  (0) 2014.12.01
Java Reflection - Methods  (0) 2014.12.01
Java Reflection - Fields  (0) 2014.12.01
Java Reflection - Constructors  (0) 2014.12.01
: