만족

[Android] 'int java.math.RoundingMode.ordinal()' on a null object reference 본문

[Android] 'int java.math.RoundingMode.ordinal()' on a null object reference

FrontEnd/Android Satisfaction 2021. 6. 23. 21:14

위의 Object를 read한 후, 그것을 write하고 다시 read하려고 할 때 발생한 예외이다.

신기한 것은 처음 read했을 때는 문제가 발생하지 않고,
그 데이터를 write한 다음, 다시 read했을때만 오류가 발생한다.

W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.math.RoundingMode.ordinal()' on a null object reference at java.text.DecimalFormat.convertRoundingMode(DecimalFormat.java:4129) at java.text.DecimalFormat.readObject(DecimalFormat.java:4397) at java.lang.reflect.Method.invoke(Native Method) at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1066) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2013) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1899) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412) W/System.err: at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2114) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2038) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1899) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412)

스택을 따라가보니 다음 코드에서 NullPointerException이 발생하는 원인이 생기는 것으로 추정된다.
(DecimalFormat.java: 4397)

fields.get()부분에서 Null을 반환한 후, setRoundingMode에서 전달된 값이 null일 경우 NPE를 발생시킨다.

그렇다면 write에서 예외가 발생해 쓰기 작업 자체에 문제가 생긴 것인가? 하고 디버깅을 해 봤지만,
write에서는 예외가 발생하지 않는다.

검색해봐도 명쾌한 해결법은 나오지 않아서, 우회하는 방법으로 문제를 해결했다.

해결법1

사실 나의 경우에는 Open_SearchDateRange라는 클래스를 다른 클래스에서 포함하기 때문에 Serializable하게 두었을 뿐,
start, end값을 제외한 ~~format들은 은 불변값이기 때문에 굳이 Serializable할 필요가 없다.

따라서 static키워드를 사용해, 다른 클래스의 수정을 유발하지 않고
Serialize/Deserialize의 대상이 되지 않게 수정했다.

해결법 2

Format Template이 가변값이라면 골치아파진다.

그래도 약간의 꼼수를 통해 수정해보자.

어차피 우리가 필요한 값은 formatter 그 자체가 아니라,
format시 어떤 템플릿을 사용할 거냐? 이기 때문에
템플릿을 스트링으로 따로 빼서 Serialize/Deserialize에는 문제가 없게 변경해 주고,

이런식으로 메소드를 거쳐 사용하도록 하면 문제가 해결된다.

해결법3

해결법2을 조금 더 응용한 방법이다.

   //...
   public String dateFormatTemplate= "yyyy-MM-dd HH:mm";
   private transit SimpleDateFormat dateFormat= null;
   //...
   public Open_SearchDateRange(){ 
     dateFormat= new SimpleDateFormat(dateFormatTemplate); 
   } 
   //... 
 }

transit 키워드를 사용해, SimpleDateFormat타입의 Object를 Serialize 대상에서 제외한다.

그렇게 하면 Serialize 작업 시 transit 키워드가 붙은 멤버 값은 무조건 null로 다뤄진다.

(null값은 아예 Serialize/Deserialize 대상이 아니기 때문에, Serializable하지 않은 타입도 올 수 있다)

String dateFormatTemplate는 Serialize/Deserialize에 문제가 없으므로,
Deserialize가 완료된 후 기본 생성자에서 dateFormat을 할당해주는 방식으로 문제를 회피할 수 있다.



Comments