DAY38
✍️어노테이션
[실행순서]
Test -> AnnotationTest (메소드 실행 테스트) -> Testclass (어노테이션 적용)
1. Testclass에 메소드를 많이 만들어 놓고 Test의 어노테이션을 적용
2. AnnotationTest (메소드 실행 테스트) 확인 (성공, 실패 카운트) - 성공을 했는지 실패를 했는지
//Test
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) // 런타임시에 정보를 클래스에 저장하겠다.
public @interface Test {
}
import java.lang.reflect.*;
public class AnnotationTest {
// ()안에 클래스를 받아서 해당 클래스의 메소드를 실행 상태 카운트 할 메소드
public static void test(Class clazz) throws Exception{
int passed = 0; // 메소드 실행 성공 카운트
int faild = 0; // 메소드 실행 실패 카운트
for(Method m : clazz.getMethods()) { // 전체 6개의 메소드를 리턴해서 루프를 돈다.
if(m.isAnnotationPresent(Test.class)) { //prn1() , prn3() , prn5()
try {
m.invoke(null); // 호출실행
passed++;
System.out.println(m.getName());
}catch(Throwable e){
System.out.println("메소드 테스트 실패 : " + e.getCause()+"\t"+m.getName());
faild++;
}
}//if
}//for
System.out.printf("실행 성공 %d 실패 %d",passed,faild);
}//method
}//class
public class Testclass {
public static void prn() {
// 어노테이션 Test를 안걸어놓아서 AnnotationTest if문 실행X
}
@Test
public static void prn1() throws Exception {
throw new Exception("에러를 내본다");
}
public static void prn2() {}
@Test
public static void prn3() {
throw new RuntimeException("에러를 내볼까?");
}
public static void prn4() {}
@Test
public static void prn5() {}
public static void main(String[] args) throws Exception {
AnnotationTest.test(Testclass.class); // 랜덤은 아니고 쓰레드 형식으로 출력? -> 순서 중요 x
}
}
- 여러개의 어노테이션을 만들 때는 접근제한자 x
- 각각의 Retention 줘야함
선언된 필드의 getter/setter 기능을 제어하는 기능을 어노테이션으로 구현 해보자.
//PrintToString.java (어노테이션)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//실행 시점에서 어노테이션의 정보를 클래스에 저장하고 필드 위에 선언되어 적용한다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface PrintToString {
}
public class Student {
@PrintToString
private String name;
@PrintToString
private int age;
@PrintToString
private String remark;
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;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
@Override
public String toString() {
//return "Student [name=" + getName() + ", age=" + getAge() + ", remark=" + getRemark() + "]";
return ToStringHelper.toString(this);
}
public static void main(String[] args) {
Student sm = new Student();
sm.setName("길동 프로님");
sm.setAge(30);
sm.setRemark("월요일은 힘들다");
System.out.println(sm);
}
}
import java.lang.reflect.*;
// getter & setter 메소드의 원형을 만드는 코드를 작성하고
// 메소드를 찾아서 리턴하는 코드를 가진 메소드를 작성한다.
public class BeansHelper {
//어노테이션이 필드에 선언되어 있기 때문에 선언된 필드로 getter/setter 원형을 찾아서
//메소드를 제어하려한다.
//getter에 해당하는 메소드 원형
public static Method getGetterMethod(Class clazz, Field field) throws Exception{
String prefix = "get";
if(Boolean.class == field.getType() || boolean.class == field.getType()) {
prefix = "is";
}
return getBeansMethod(clazz,field,prefix);
}
//setter에 해당하는 메소드 원형
public static Method getSetterMethod(Class clazz, Field field,Class...paramType) throws Exception{
return getBeansMethod(clazz,field,"set",paramType);
}
//메소드로 만들어서 리턴해준다.
private static Method getBeansMethod(Class clazz, Field field, String prefix, Class... paramType)throws Exception {
// name -> getName() -> get + Fieldname
//getBeansMethod(clazz,field,prefix) -> (Student,name,get)
String fieldName = field.getName();
fieldName = prefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); //getName
Method method = clazz.getMethod(fieldName, paramType);
return method;
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//getter 메소드를 리턴받아 / 출력하는 구문을 작성하는 클래스와 메소드
public class ToStringHelper {
public static String toString(Object obj) {
StringBuffer buffer = new StringBuffer();
try {
//1. 지정된 obj로 넘겨 받은 객체를 클래스로 변환
Class clazz = obj.getClass(); //Student
buffer.append(clazz.getName()).append("{");
//2. 변환된 클래스의 필드를 반복문을 이용해서 추출한다.
for(Field field : clazz.getDeclaredFields()) {
//3. 전체 필드중에 PrintToString 어노테이션이 있는 필드를 추출한다.
PrintToString pts = field.getAnnotation(PrintToString.class);
//4. 조건문을 이용해서 null값이 아닌 클래스와 필드를 통해 get메소드를 실행한다.
if(pts != null) {
Method getter = BeansHelper.getGetterMethod(clazz, field);
System.out.println(getter);
Object value = getter.invoke(obj);
buffer.append(field.getName()).append("=").append(value).append(",");
} //if
} //for
buffer.append("}");
}catch(Exception e) {
}
return buffer.toString();
}//method
}//class