오늘은 jsr305 스펙에 대해서 몇가지 알아보자.
jsr305 는 소프트웨어 결함 탐지를 위한 어노테이션이다. 이렇게 말하면 뭔말인지 모르니 한번 해보도록하자.
com.google.code.findbugs
의 jsr305를 디펜더스 받자. 왜 google로 되어있는지는 모르겠다. 만든 사람이 구글에 다니던 시절에 만들어서 그런가?
findbugs
프로젝트보면 다양한게 많이 있는 듯한데.. 자세히는 보지 않았다.
일단 아래와 같이 디펜더시를 받자.
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
그리고 나서 하나씩 살펴보도록 하자. 일단 기준은 IDEA이다. 이클립스나 넷빈즈는 어떻게 동작하지는 잘 모르겠다.
스펙들은 아주 많은데 그 중에 IDEA가 지원해주거나 혹은 자주 사용할 것 같은 어노테이션 위주로 살펴보도록 할 것이다.
@Nonnull
null이 아님을 의미한다. 이 어노테이션이 붙는 다면 null이 아니여야 한다. 파라미터나 리턴(메서드위)에 이 어노테이션을 넣을 수 있다. 인텔리 기준에서는 해당 메서드를 호출시 힌트가 발생한다.
public static int getLength(@Nonnull String name) {
return name.length();
}
만약 위와 같은 코드가 있을 때 꼭 null이 아니여야 하므로 이 코드를 호출시에 null을 넣으면 경고(?) 힌트가 발생한다.
getLength(null); // null 에 힌트
또 한 이렇게 메서드를 호출시에는 NPE이 발생하지 않고 다른 에러가 발생한다.
Exception in thread "main" java.lang.IllegalArgumentException: Argument for @Nonnull parameter name of me/wonwoo/ClassTest.getLength must not be null
위와 같은 에러? 실제 컴파일을 해서 바이트코드를 보면 null 체크하는 코드가 삽입되서 들어간다. 파라미터뿐만 아니라 리턴타입에 넣어도 된다.
@Nonnull
public static Integer getLength(@Nonnull String name) {
return null; //null 에 힌트
}
@Nullable
@Nonnull 어노테이션과는 반대의 의미를 가지고 있다. null이 가능하다는 것을 의미한다. 역시 파라미터뿐 아니라 리턴타입에도 넣을 수 있다.
@Nullable
public static Integer getLength(@Nullable String name) {
return name.length(); // 힌트
}
final Integer length = getLength("null");
length.toString(); //힌트
파라미터 name은 null이 들어 올 수 있으므로 NPE 발생할 여지가 있다. 그래서 length()를 그대로 호출 하면 안된다는 것이다.
@CheckReturnValue
위 어노테이션은 리턴 값 꼭 받아서 확인하라는 어노테이션이다.
@CheckReturnValue
public static Integer getLength(String name){
return name.length();
}
getLength("null"); //힌트
getLength() 메서드를 호출할 때 리턴을 받지 않아 힌트가 주어졌다.
@OverridingMethodsMustInvokeSuper
이 어노테이션은 만약 슈퍼클래스의 메서드를 오버라이딩 할 때 꼭 슈퍼 클래스의 메서드를 호출 하라는 뜻 이다.
class SuperClass {
@OverridingMethodsMustInvokeSuper
public String name() {
return "wonwoo";
}
}
class SubClass extends SuperClass {
@Override
public String name() { //메서드 힌트
return "won";
}
}
SuperClass의 name 메서드를 오버라이딩 했지만 SuperClass의 name() 메서드를 호출하지 않아 메서드에 힌트가 발생하였다.
@ParametersAreNullableByDefault
@Nonnull 과 동일한 거 같은데? 이것은 파라미터에만 적용된다.
@ParametersAreNullableByDefault
public static List<String> lists(List<String> list) {
if(list != null) {
list.size();
}
list.size(); //힌트
return list
}
파리미터
List<String> list
는 null이 가능하므로 if 문 밖에 있는 list.size()에 힌트가 주어졌다. null이 가능하므로 null 체크를 해줘야 할 것이다.
@ParametersAreNonnullByDefault
@ParametersAreNullableByDefault 이 어노테이션과는 반대되는 어노테이션이다. 파라미터가 null이 아니여야 한다는 뜻이다.
@ParametersAreNonnullByDefault
public static List<String> lists(List<String> list) {
if(list != null) { //힌트
list.size();
}
list.size();
return list;
}
파라미터가 null이 아니여야 하므로 굳이 null 체크를 할 필요가 없다는 뜻이다. 그래서 null 체크 부분에서 힌트가 주어졌다.
일단 jsr305 어노테이션을 IDEA가 지원해주는 것은 여기까지 인 듯 하다. 더 있을 수는 있겠지만 그닥 사용하지 않을 듯 해서 살펴보지 않았다. 지원은 해주지 않지만 자주 사용할만한 어노테이션은
@Immutable
,
@NotThreadSafe
,
@ThreadSafe
이정도가 더 있을 듯하다.
이런 어노테이션을 통해 어느정도는 버그들을 잡을수(?) 있을 듯 하다. nullPointException만 잡아도 어느정도(?) 버그는 잡지 않을까? 예전에 어느 기사였나 블로그 였나? 자바의 가장 많이 발생하는 exception이
nullPointException
이라 했던 기억이 어렴풋이 난다. 암튼 null이란..
아무튼 이렇게 jsr305 어노테이션을 사용해서 아니
@Nonnull
,
@Nullable
이정도면 사용해도 어느정도 괜찮을 듯 하다.
null 만이라도 잡자!