728x90
반응형
Json
- json.Unmarshal 을 할 때 에러 발생 시 타입이 json 타입이 아니게 되면 오류가 발생 할 수 있다.
- 오류 발생 시 변환 데이터와 변환하려는 타입을 알 수 없어 어떤 값인지 알기 어렵다.
Unmarshal 함수 생성
- 로깅을 위한 ErrorData 구조체를 생성하여, 덕 타이핑을 통해 error interface type에 속하게 한다.
- Unmarshal 실패 시 error 데이터를 ErrorData 구조체에 할당하여 반환한다.
- ErrorData에 unmarshaling하려던 데이터를 InputData field에, 값을 저장할 데이터의 타입을 TargetType field에 저장하고, unmarshaling 실패 에러를 Err field에 저장한다.
- ErrorData 구조체의 포인터 리시버로 UnmarshalJSON함수를 생성하여 unmarshal 시 해당 함수를 이용하게 한다.
- MashalJSON은 ErrorData의 메소드로 작성한다.
- ErrorData를 marshal or unmarshal 시 아래 생성한 함수가 호출된다.
type ErrorData struct {
InputData string `json:"input_data"`
Err error `json:"-"`
TargetType string `json:"target_type"`
}
func (e *ErrorData) UnmarshalJSON(data []byte) (err error) {
defer util_error.DeferWrap(&err)
type E ErrorData
errorDataInner := &struct {
*E
ErrorString *string `json:"error"`
}{
E: (*E)(e),
}
err = json.Unmarshal(data, errorDataInner)
if err != nil {
return
}
if errorDataInner.ErrorString != nil {
e.Err = errors.New(*errorDataInner.ErrorString)
}
return
}
func (e ErrorData) MarshalJSON() ([]byte, error) {
var err error
defer util_error.DeferWrap(&err)
type E ErrorData
errorDataInner := &struct {
*E
ErrorString *string `json:"error"`
}{
E: (*E)(&e),
}
if e.Err != nil {
errString := e.Err.Error()
errorDataInner.ErrorString = &errString
}
data, err := json.Marshal(errorDataInner)
return data, err
}
func (e *ErrorData) IsError() bool {
return e.Err != nil
}
func (e *ErrorData) Error() string {
return utils.Join("error: ", e.Err.Error(), ", inputData: ", e.InputData, ", TargetType: ", e.TargetType)
}
func Unmarshal(data []byte, v any) (errorData error) {
err := json.Unmarshal(data, v)
if err == nil {
return
}
TargetType := reflect.TypeOf(v)
errorData = &ErrorData{
InputData: string(data),
Err: err,
TargetType: TargetType.String(),
}
return
}
오류 상황
// ErrorStruct의 포인터 리시버인 UnmarshalJSON함수 내에서 json.Unmarshal(data, &errorData)로 하여 무한루프로 호출되었던 문제
// 문제 코드
func (e *ErrorData) UnmarshalJSON(data []byte) (err error) {
defer util_error.DeferWrap(&err)
err = json.Unmarshal(data, e)
if err != nil {
return
}
return
}
// 해결 -> 임시 구조체를 만들어서 ErrorStruct를 내부 포인터 필드로 갖도록 하여 unmarshaling을 한다.
// 수정 코드
func (e *ErrorData) UnmarshalJSON(data []byte) (err error) {
defer util_error.DeferWrap(&err)
type E ErrorData
errorDataInner := &struct {
*E
ErrorString *string `json:"error"`
}{
E: (*E)(e),
}
err = json.Unmarshal(data, errorDataInner)
if err != nil {
return
}
if errorDataInner.ErrorString != nil {
e.Err = errors.New(*errorDataInner.ErrorString)
}
return
}
728x90
반응형
'Golang' 카테고리의 다른 글
[Golang] interface addressable (0) | 2023.05.10 |
---|---|
[Golang] interface 타입 nil 체크 (3) | 2023.02.09 |
[Golang] iota (0) | 2022.11.20 |
Error Is, As (0) | 2022.10.15 |
[Golang] Closure (0) | 2022.04.18 |