변수는 다음과 같이 myAge와 defaultAge 두 가지인데 myAge에 어노테이션에서는 30으로 값을 주입합니다. 하지만 defaultAge 에서는 값이 없는데 이 경우 어노테이션에서 정한 기본 값인 0으로 값이 주입이 됩니다. 생성자의 경우 값이 없을 경우 -1을 기본으로 저장합니다.
다음은 두 번째 예제인 문자열 값 주입을 보도록 하겠습니다. 두 번째 예제에서는 수행 클래스 및 실행 클래스까지 알아보겠습니다.
publicAnnotationExam02(){ myData = "No data"; defaultData = "No data"; }
public String getMyData(){ return myData; }
public String getDefaultData(){ return defaultData; } }
변수는 다음과 같이 myData와 defaultData 두 가지인데 myData에 어노테이션에서는 “MHLab”으로 값을 주입합니다. 하지만 defaultData 에서는 값이 없는데 이 경우 어노테이션에서 정한 기본 값인 “default”로 값이 주입이 됩니다. 생성자의 경우 값이 없을 경우 “No data” 문자열을 기본으로 저장합니다.
약간 코드가 복잡한데 하나씩 설명드리겠습니다. (코드 리펙토링이 필요하지만 예제를 위한 코드이기에 그냥 진행하겠습니다.)
getInstance 메서드
이 메서드는 두 가지의 전달인자를 받습니다. 첫 번째는 어노테이션이 적용되어 있는 2번에서 작성한 클래스, 두 번째는 체크할 어노테이션 클래스입니다. 반환 값은 Optional을 사용하여 반환하게 됩니다. 먼저 타겟 클래스의 인스턴스를 생성하고, checkAnnotation 메서드를 호출합니다. 여기서 전달인자에 어노테이션 클래스를 넣은 것은 향후 확장성을 고려 하였는데, 이 부분은 기호에 알맞게 메서드를 나눠서 구현을 해도 무방합니다.
checkAnnotation 메서드
이 메서드는 앞선 getInstance 메서드의 전달인자를 그대로 받습니다. fields 변수는 타겟 객체에 선언된 것들을 모두 가져옵니다. (Field는 리플렉션과 관련되어 있고, 이는 다음 포스팅에서 다루겠습니다.) 그 다음 전달인자 annotationObj 값에 따라 분기를 나눠 메서드를 호출하게 됩니다.
checkAnnotation4InsertInt 메서드 (checkAnnotation4InsertString 메서드도 동작이 비슷하게 여기 설명으로 대체합니다.)
해당 메서드는 한 라인씩 간략하게 짚고 넘어가겠습니다
InsertIntData annotation = field.getAnnotation(InsertIntData.class); 이 부분은 전달인자로 받은 Field에서 선언된 어노테이션을 가져옵니다.
if(annotation != null && field.getType() == int.class) 이 부분은 어노테이션이 null이 아니거나 선언된 변수의 타입이 int형일 경우에만 수행을 하게 됩니다.
field.setAccessible(true); 일반적으로 private로 선언된 변수(필드)의 경우 접근이 불가능하지만, 리플렉트를 통한 접근에 한하여 가능하게끔 해준다.
try { field.set(targetObj, annotation.data()); } 해당 변수의 값을 어노테이션의 값으로 치환하게 됩니다.
위와 같은 작업을 거치고 난 후 전달인자로 넘어온 어노테이션이 선언된 클래스 객체를 반환하게 됩니다.