반응형

 

Annotation

 

: 프로그램 소스코드 안에서 다른 프로그램을 위한 정보를 제공하는 주석처럼 사용되는 기술을 말한다.

프로그램에 영향을 미치지 않으며 프로그램에게 유용한 정보제공한다.

 

 

- 종류

1. 표준애너테이션 : 자바에서 기본적으로 제공하는 애너테이션

2. 메타애너테이션 : 어노테이션에 붙이는 어노테이션. 어노테이션을 정의하는 데 사용하며 어노테이션의 적용대상 또는 어노테이션을 유지하는 시간 등을 규정한다.

 

 

- 애너테이션 요소의 규칙

1. 요소타입은 기본형, String, enum, annotation, Class만 허용된다.
2. ()안에 매개변수를 선언할 수 없다.
3. 예외를 선언할 수 없다.
4. 요소타입에 제너릭타입글자를 사용할 수 없다.

 

 

 

  • 사용법
@interface 애너테이션 이름 {
 		요소타입 타입요소이름(); // 반환값이 있고 매개변수는 없는 추상메서드의 형태
 			...
}

 

 

package kr.or.ddit.basic;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
 * Annotation 에 대하여...
 * 
 * 프로그램 소스코드 안에서 다른 프로그램을 위한 정보로 미리 약속된 형식으로 포함시킨 것(JDK1.5부터 지원)
 * 
 * 주석처럼 프로그램에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공함.
 * 
 * 종류 :	1. 표준애너테이션 
 * 		2. 메타애너테이션(애너테이션을 위한 애너테이션, 즉 애너테이션을 정의할 때 사용하는 애너테이션)
 * 
 * 애너테이션 타입 정의하기
 * @interface 애너테이션 이름 {
 * 		요소타입 타입요소이름(); // 반환값이 있고 매개변수는 없는 추상메서드의 형태
 * 			...
 * 	}
 * 
 * 애너테이션 요소의 규칙
 * 	1. 요소타입은 기본형, String, enum, annotation, Class만 허용된다.
 *  2. ()안에 매개변수를 선언할 수 없다.
 *  3. 예외를 선언할 수 없다.
 *  4. 요소타입에 제너릭타입글자를 사용할 수 없다.
 */

@Target({ElementType.METHOD, ElementType.TYPE}) // 적용가능 대상 지정함
@Retention(RetentionPolicy.RUNTIME) // 유지되는 기간 지정함.
public @interface PrintAnnotation {
	String value() default "-"; // 디폴트로 -값이 지정됨
	int count() default 20;
}

 

 

package kr.or.ddit.basic;

public class Service {
	
	// 아무것도 안 넣기에 value -, count 20이 디폴트로 주어진 것
	@PrintAnnotation
	public void method1() {
		System.out.println("메서드1이 호출되었습니다.");
	}
	
	@PrintAnnotation(value = "%")
	public void method2() {
		System.out.println("메서드2이 호출되었습니다.");
	}
	
	@PrintAnnotation(value = "#", count = 25)
	public void method3() {
		System.out.println("메서드3이 호출되었습니다.");
	}
}

 

 

 

  • PrintAnnotation 확인 예시
package kr.or.ddit.basic;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class AnnotationTest {
	public static void main(String[] args) {
		Method[] methodArr = Service.class.getDeclaredMethods();
		
		for (Method m : methodArr) {
			System.out.println("메서드 명 : " + m.getName());
			Annotation[] annos = m.getDeclaredAnnotations();
			
			for (Annotation anno : annos) {
				if(anno.annotationType().getSimpleName().equals("PrintAnnotation")) {
					PrintAnnotation printAnno = (PrintAnnotation) anno;
					int count = printAnno.count();
					String value = printAnno.value();
					
					for(int i=0; i<count; i++) {
						System.out.print(value);
					}
				}
			}
			System.out.println(); // 줄바꿈 처리
		}
	}
}

 

결과 화면1 : method1은 20번, method2는 20번, method3은 25번 출력됨

 

 

 

리플렉션 사용

 

어노테이션 정보를 접근해 보기 위해 리플렉션을 사용한다.

 

- 순서

1. 클래스 오브젝트생성하여 클래스의 정보를 가져옴

2. 클래스의 메타데이터 가져옴

 

 

  • Java Reflection

1. 리플렉션은 런타임 시점에 클래스 또는 멤버변수, 메서드, 생성자 등에 대한 정보를 가져오거나 수정할 수 있고, 새로운 객체를 생성하거나 메서드를 실행할 수 있다. (컴파일 시점에 해당정보를 알 수 없는 경우(소스코드의 부재)에 유용하게 사용될 수 있다.)
2. 리플렉션 API는 java.lang.reflect 패키지와 java.lang.Class를 통해 제공된다.
3. java.lang.Class의 주요 메서드
  - getName(), getSuperClass(), getInterfaces(), getModifiers() 등.
4. java.lang.reflect 패키지의 주요 클래스
  - Field, Method, Constructor, Modifier 등.

 

 

 

  • Class 오브젝트(클래스정보를 담고 있는 객체)를 생성하기
package kr.or.ddit.ref;

/**
 * Class 오브젝트(클래스정보를 담고 있는 객체)를 생성하기
 */
public class T01ClassObjectCreationTest {
	/*
	 * Java Reflection 에 대하여...
	 * 
	 * 1. 리플렉션은 런타임 시점에 클래스 또는 멤버변수, 메서드, 생성자 등에 대한 정보를 가져오거나 수정할 수 있고,
	 * 	새로운 객체를 생성하거나 메서드를 실행할 수 있다.
	 * 	(컴파일 시점에 해당정보를 알 수 없는 경우(소스코드의 부재)에 유용하게 사용될 수 있다.)
	 * 2. 리플렉션 API는 java.lang.reflect 패키지와 java.lang.Class를 통해 제공된다.
	 * 3. java.lang.Class의 주요 메서드
	 * 	- getName(), getSuperClass(), getInterfaces(), getModifiers() 등.
	 * 4. java.lang.reflect 패키지의 주요 클래스
	 * 	- Field, Method, Constructor, Modifier 등.
	 */
	
	public static void main(String[] args) throws ClassNotFoundException {
		// 방법1 : Class. forName(클래스 이름) 메서드 이용하기
		// 클래스 이름에 대한 정보를 klass에 저장
		Class<?> klass = Class.forName("kr.or.ddit.ref.T01ClassObjectCreationTest");
		
		// 방법2 : getClass() 메서드 이용하기
		klass = new T01ClassObjectCreationTest().getClass();
		
		// 방법3 : .class 이용하기
		klass = T01ClassObjectCreationTest.class;
	}
}

 

 

 

  • 클래스의 메타데이터 가져오기 - 예시 1
package kr.or.ddit.ref;

import java.io.Serializable;

public class SampleVO implements Serializable{
	private String id;
	protected String name;
	public int age;
	
	public SampleVO(String id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}
	
	public SampleVO() {
		
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

 

package kr.or.ddit.ref;

import java.lang.reflect.Modifier;

/**
 * Class의 메타데이터 가져오기
 */
public class T02ClassMetadataTest {
	public static void main(String[] args) {
		
		// 클래스 오브젝트 생성하기
		Class<?> clazz = SampleVO.class;
		
		System.out.println("심플클래스명 : " + clazz.getSimpleName());
		System.out.println("클래스명 : " + clazz.getName());
		System.out.println("상위 클래스명 : " + clazz.getSuperclass().getName());
		
		// 패키지 정보 가져오기
		Package pkg = clazz.getPackage();
		System.out.println("패키지 정보 : " + pkg.getName());
		System.out.println();
		
		// 해당 클래스에서 구현하고 있는 인터페이스 목록 가져오기
		Class<?>[] interfaces = clazz.getInterfaces();
		
		System.out.println("인터페이스 목록 => ");
		for (Class<?> inf : interfaces) {
			System.out.println(inf.getName() + " | ");
		}
		System.out.println();
		
		// 클래스의 접근제어자 정보 가져오기
		int modFlag = clazz.getModifiers();
		
		System.out.println("접근제어자 정보 : " + Modifier.toString(modFlag));
	}
}

 

결과 화면2

 

 

 

  • 클래스의 메타데이터 가져오기 - 예시 2
package kr.or.ddit.ref;

import java.io.Serializable;

import kr.or.ddit.basic.PrintAnnotation;

public class SampleVO implements Serializable{
	private String id;
	protected String name;
	public int age;
	
	public SampleVO(String id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}
	
	public SampleVO() {
		
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	@PrintAnnotation
	public void setName(String name) throws Exception{
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

 

package kr.or.ddit.ref;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 클래스에 선언된 메서드의 메타정보 가져오기
 */
public class T03MethodMetadataTest {
	public static void main(String[] args) throws ClassNotFoundException {
		// Class 객체 생성
		Class<?> klass = Class.forName("kr.or.ddit.ref.SampleVO");
		
		// 클래스에 선언된 모든 메서드 정보 가져오기
		// 메소드 타입의 배열로 가져오게 됨.
		Method[] methodArr = klass.getDeclaredMethods();
		
		for (Method m : methodArr) {
			System.out.println("메서드 명 : " + m.getName());
			System.out.println("메서드 리턴타입 : " + m.getReturnType());
			
			// 해당 메서드의 접근제어자 정보 가져오기
			int modFlag = m.getModifiers();
			System.out.println("메서드 접근제어자 : " + Modifier.toString(modFlag));
			System.out.println();
			
			// 해당 메서드의 파라미터 정보 가져오기
			Class<?>[] paramArr = m.getParameterTypes();
			System.out.println("메서드 파라미터 타입 => ");
			for (Class<?> clazz : paramArr) {
				System.out.println(clazz.getName() + " | ");
			}
			System.out.println();
			
			// 해당 메서드에서 던지는 예외타입 가져오기
			Class<?>[] exTypeArr = m.getExceptionTypes();
			System.out.println("메서드에서 던지는 예외타입 목록 : ");
			for (Class<?> clazz : exTypeArr) {
				System.out.println(clazz.getName() + " | ");
			}
			System.out.println();
			
			// 해당 메서드에 존재하는 Annotation 타입정보
			Annotation[] annos = m.getDeclaredAnnotations();
			System.out.println("Annotation 타입 => ");
			for (Annotation anno : annos) {
				System.out.println(anno.annotationType().getName() + " | ");
			}
			System.out.println();
			System.out.println("-----------------------------------------------------");
		}
	}
}

 

결과 화면3-1

 

결과 화면3-2

 

 

반응형