외부 서버와 통신할 때, 결과를 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 가 발생한다.


 


http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Enum.java#Enum.valueOf%28java.lang.Class%2Cjava.lang.String%29


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)))

 // 정상 처리

}






Posted by 김용환 '김용환'

댓글을 달아 주세요