아이템 39. 명명 패턴보다 애너테이션을 사용하라
ksy90101 opened this issue · 4 comments
아이템 39-3 마커애너테이션을 처리하는 프로그램에서 리플렉션 처리 과정 중 궁금한 점이 있습니다.
예시는 아래와 같았는데
public class RunTests {
public static void main(String[] args) throws Exception {
int tests = 0;
int passed = 0;
Class<?> testClass = Class.forName(args[0]); // item39.Sample
for (Method m : testClass.getDeclaredMethods()) { // 리플렉션으로 사용할 메서드 m1, m2...
if (m.isAnnotationPresent(Test.class)) { // @Test 어노테이션이 있으면
tests++;
try {
m.invoke(null); // 실제 메서드 실행
passed++; // 성공하면 passed++
} catch (InvocationTargetException wrappedExc) { // 테스트에서 예외를 던지면 리플렉션 매커니즘이 InvocationTargetException으로 감싸서 다시 던진다.
Throwable exc = wrappedExc.getCause();
System.out.println(m + " 실패: " + exc);
} catch (Exception exc) {
// 테스트에서 잡지 못한 예외가 있다는것은 @Test 애너테이션을 잘못 사용했다는 뜻.
System.out.println("잘못 사용한 @Test: " + m);
}
}
}
System.out.printf("성공: %d, 실패: %d%n",
passed, tests - passed);
}
}
@test 어노테이션을 달아둔 메서드가 실패하면 InvocationTargetException 으로 들어오고, @test 어노테이션을 잘못 사용할 경우에는 Exception 이 발생한다고 되어 있었습니다, 리플렉션에서는 메서드 내부에서 Exception이 발생하면 무조건 InvocationTargetException 으로 던지게 된다고 써있는데, 실제로 익셉션이 NullPointException, IlligalException, ClassCastExcpetion 등이 발생할 요소가 있고 이런 것을 분리해서 롤백/확인을 하고 싶다면 어떻게 해야 하나요?
리플렉션에서는 무조건 InvocationTargetException으로 던지는건 신기하네요 ㅋㅋㅋ
Throwable exc = wrappedExc.getCause();
에서 실제 메서드에서 발생한 root cause를 가져올 수 있는걸로 보이네요. 이를 활용하면 되지 않을까 싶어요.
벨덩(?)에서도 Throwable.getCause()
를 활용하라고 하네요
@pkch93 아하! 그럼 getCause()로 나온 Exception 이름들을 클래스 이름으로 분기태워서 해야겠네요.
InvocationTargetException에서 getCause()메서드와 함께 getTargetException()도 있길래 실험해보는데 동일하게 Exception 이름이 반환되네요. cause랑 동일한 역할을 하는 친구인 것 같습니다.
네넵 getCause()
랑 getTargetException()
이랑 동일한 역할을 하네요 ㅋㅋ
public Throwable getTargetException() {
return target;
}
public Throwable getCause() {
return target;
}
스프링도 리플렉션을 사용하고 있어서 어떻게 처리하나 봤는데 getTargetException()
으로 실제 발생한 Exception을 가져와서 분기처리하네요.
org.springframework.web.method.support.InvocableHandlerMethod
입니다.
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}