Chapter 10-1
Annotation Define
예제 코드
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
String value() default "";
}
//....
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value() default "";
RequestMethod method() default RequestMethod.GET;
}
Controller @interface 코드를 예로 들면
value라는 변수를 입력받을 수 있고 default는 ““로 입력할 수 있게 정의한것이다.
@Controller(value = "temp")
와 같이 사용할 수 있고 value를 지정하지 않으면 default 값인 ““이 저장될 것이다.
@Target Annotation
어노테이션을 지정할 수 있는 타입을 설정
Enum형인 ElementType를 이용하여 지정할 수 있다.
- PACKAGE : 패키지 선언시
- TYPE : 타입 선언시
- CONSTRUCTOR : 생성자 선언시
- FIELD : 멤버 변수 선언시
- METHOD : 메소드 선언시
- ANNOTATION_TYPE : 어노테이션 타입 선언시
- LOCAL_VARIABLE : 지역변수 선언시
- PARAMETER : 파라미터 선언 시 ex)
@RequestParam
or@Params
등.. - TYPE_PARAMETER : 파라미터 타입 선언 시
List<@NotNull String> arr = ...;
- TYPE_USE : 타입 사용시
@Retention Annotation
- 어노테이션의 scope를 나타낸다.
- Enum형인 RetentionPolicy를 이용하여 어노테이션의 범위를 지정할 수 있다.
- RetentionPolicy
- RUNTIME : 런타임 중에도 JVM에 의해 참조가 가능하다.
- CLASS : 컴파일 시 사용되고 .class 파일에 저장된다. 런타임시 사용하지 않음
- SOURCE : 컴파일시까지만 사용되고 .class 파일에 저장되지 않는다.
Java reflection (자바 리플렉션)
자바 객체를 통해 클래스 정보를 알아내는 기법
ex)
Object obj = new String();
인스턴스는 String 인스턴스지만 Object형에 담았기 때문에 String에 있는 메서드나 멤버 변수는 사용할 수 없다.
위와 같은 경우에 자바 리플렉션 기법을 활용하면 인스턴스 객체를 가지고 클래스 정보를 알아낸 후 해당 인스턴스의 메서드를 호출 하거나 멤버 변수에 접근할 수 있다.
여러가지 API들과 메서드들 정리
java.lang.Class API
- getFields() : 해당 클래스의 public 멤버 변수를 조회
- getDeclaredFields() : 해당 클래스의 모든 멤버 변수를 조회
- getConstructors() : 해당 클래스의 public 생성자를 조회
- getDeclaredConstructors() : 해당 클래스의 모든 생성자를 조회
- getMethods() : 해당 클래스의 public 메서드를 조회
- getDeclaredMethods() : 해당 클래스의 모든 메서드를 조회
method.invoke
- Method 클래스의 invoke 메서드는 invoke 메서드 인자로 넘어온 인스턴스의 해당 메서드가 있으면 그 메서드를 호출한다.
method.isAnnotationPresent(Class clazz)
- 해당 clazz Class에 어노테이션이 있는지 확인하는 메서드
clazz.newInstance()
- 기본 생성자를 호출해준다. 기본 생성자가 없으면 호출할 수 없다.
- 기본 생성자가 없는 경우 getDeclaredConstructors()를 통해 생성자를 찾을 수 있다.
- constructor.newInstance(Object… args)로 인스턴스를 생성한다.
필드 접근
getDeclaredField(String name)을 이용하여 private 필드를 찾는다.
private 필드에 접근하기 위해선 접근 권한을 수정해야한다
Field.setAccessible(true)
- setAccessible을 설정하면 Field 클래스에 Override 속성이 true로 변경됨
field.set(student, "테스트")
와 같이 private 필드에 값을 할당할 수 있다.예제코드
@Test public void test1() throws IllegalAccessException, InstantiationException { TranslationParam translationParam = new TranslationParam() ; Class test = TranslationParam.class; TranslationParam param = (TranslationParam) test.newInstance(); Method[] methods = test.getMethods(); Field[] fields = test.getDeclaredFields(); fields[0].set(param, "test0"); // public 필드는 바로 set 가능 // fields[1].set(param, "ddddd"); // private 필드는 set하려고하면 IllegalAccessException 발생 fields[1].setAccessible(true); // Override 속성을 true로 변경해야 함 fields[1].set(param, "test1"); }