외부 서버와 통신할 때, 결과를 enum으로 처리하는 경우가 종종 있다.
String 리턴 값을 enum으로 변환하기 위해 자바 enum 타입으로 매핑하기 위해 작업하다가 NPE가 발생할 수 있다.
java.lang.NullPointerException: Name is null
at java.lang.Enum.valueOf(Enum.java:236)
at ResultType.valueOf(ResultType.java:6) // enum이 클래스로 변환하기 때문에 정확히 코드로 보이지 않는다.
자바에서 enum을 정의하면, 자바 컴파일러에 의해 클래스로 변환된다.
(확인 방법은 http://varaneckas.com/jad/를 다운받고, http://knight76.tistory.com/entry/Jad-%EC%82%AC%EC%9A%A9%EB%B2%95로 사용한다)
public enum ResultType {
SUCCESS("success"),
ERROR("error");
//..
// 내부 enum 필드를 map으로 저장한다.
private static Map<String, String> enumMap;
public static String getResult(String name) {
if (enumMap == null) {
initializeMap();
}
return enumMap.get(name);
}
private static Map<String, String> initializeMap() {
enumMap = new HashMap<String, String>();
for (ResultType resultType : resultType.values()) {
enumMap.put(resultType.getName(), resultType.toString());
}
return enumMap;
}
}
=>
6 public final class ResultType extends Enum
7 {
...
// 새로 추가되는 메소드
50 public static ResultType valueOf(String s)
51 {
52 return (ResultType)Enum.valueOf(ResultType, s);
53 }
..
// 나머지는 그대로
외부 서버와 통신한 후, 리턴 받은 값을 enum 으로 변환하기 위해
String.valueOf()와 ResultType.getResult()를 사용하, 다시 이를 ResultType.valueOf()로 적용하면 원하는 값으로 바인딩 될 수 있다.
String result = restTemplate.exchange(...);
ResultType.valueOf(ResultType.getResult(String.valueOf(result)))
서로 약속한 값이 전달되면 문제는 없지만, 외부 통신 서버에서 결과 값을 이상하게 전달할 때, 에러가 발생한다.
String result = restTemplate.exchange(...); // enum에서 정의되지 않은 "xxxxx"라는 스트링이 도착했다.
ResultType.valueOf(ResultType.getResult(String.valueOf(result)))
==> NPE : Name is null
외부 서버가 enum에 없는 값을 보내면서 ResultType.getResult()는 null을 리턴하고, enum이 클래스로 변환하면서 만들어진 ResultType.valueOf() 메소드는 내부적으로 Enum.valueOf()를 호출한다. 이 때 두 번째 매개변수가 null이 된다. Enum.valueOf() 메소드는 내부적으로 아래와 같이 되어 있고, name이 null이면 NPE 가 발생한다.
207 public static <T extends Enum<T>> T More ...valueOf(Class<T> enumType,
208 String name) {
209 T result = enumType.enumConstantDirectory().get(name);
210 if (result != null)
211 return result;
212 if (name == null)
213 throw new NullPointerException("Name is null");
214 throw new IllegalArgumentException(
215 "No enum const " + enumType +"." + name);
216 }
따라서 외부 서버에서 들어온 값을 enum으로 변환할 때는 enum에서 선언한 필드가 아닌 값이 올 수 있고, 내부 코드에 따라 enum을 null로 바인딩될 수 있다는 것을 가정하고 코드를 짜는 것이 좋다.
String result = restTemplate.exchange(...);
if (ResultType.getResult(String.valueOf(result)) == null) {
// 통신 에러 처리
} else {
ResultType type = ResultType.valueOf(ResultType.getResult(String.valueOf(result)))
// 정상 처리
}
'java core' 카테고리의 다른 글
JVM의 safepoint (0) | 2016.09.08 |
---|---|
JDK의 Flight Recorder 라이선스 (0) | 2016.09.08 |
java7->java8 전환 관련 네트워킹 이슈 (getaddrinfo) (0) | 2016.07.26 |
java7 -> java8 전환 with spring 3.2 (1) | 2016.07.21 |
Set (유일성 보장) 사용시 객체가 구현해야 할 hashcode() (0) | 2016.06.23 |