Android프로그래밍

[안드로이드 ] Gson 사용시 JNI DETECTED ERROR IN APPLICATION: can’t make objects of type 오류(from java.lang.Object sun.misc.Unsafe.allocateInstance(java.lang.Class))가 발생할 때 해결 방법

JNI DETECTED ERROR IN APPLICATION: can’t make objects of type com.app.BearAreaVo

오래된 안드로이드 앱을 업그레이드 하는 과정에 예상치 못한 오류가 발생하여 기존에 사용하던 네트워크 호출 클래스를 제거하고

okhttps3 라이브러리를 사용하여 get방식으로 호출 후 json 문자열 데이터를 VO에 담으려고 하면서 발생한 오류이다.

오류 내용은 다음과 같다.

### jsonString2 : [{"lat":"49.254381","lon":"-122.8183091"},{"lat":"49.2958984","lon":"-122.7043395"},{"lat":"49.3578478","lon":"-123.0274911"},{"lat":"49.3342397","lon":"-123.0012486"},{"lat":"49.3475493","lon":"-122.8686121"},{"lat":"49.3199479","lon":"-122.8940357"},{"lat":"49.1807551","lon":"-122.7629478"},{"lat":"49.1912566","lon":"-122.7316538"},{"lat":"49.395506","lon":"-123.201689"},{"lat":"49.2459918","lon":"-122.5442593"},{"lat":"49.3064387","lon":"-123.0020362"},{"lat":"51.1841171","lon":"-115.5847927"},{"lat":"51.1791155","lon":"-115.6099708"},{"lat":"51.1719064","lon":"-115.4693033"},{"lat":"51.180894","lon":"-115.583712"},{"lat":"50.089398","lon":"-95.321851"},{"lat":"49.821259","lon":"-95.481628"},{"lat":"52.2901734","lon":"-119.6858619"},{"lat":"51.0497666","lon":"-123.0886179"},{"lat":"52.5954402","lon":"-126.0732929"},{"lat":"64.0686028","lon":"-147.5051942"},{"lat":"50.059988","lon":"-122.955940"},{"lat":"49.5592368","lon":"-125.403021"},{"lat":"57.7899846","lon":"-93.2418164"},{"lat":"51.3705027","lon":"-127.1028468"},{"lat":"48.7919313","lon":"-125.1585477"},{"lat":"50.8661206","lon":"-125.9815131"},{"lat":"52.8812158","lon":"-127.7398788"},{"lat":"49.232985","lon":"-122.933735"},{"lat":"51.029237","lon":"-115.258111"},{"lat":"51.496149","lon":"-115.928038"},{"lat":"52.871658","lon":"-117.954220"},{"lat":"48.9489724","lon":"19.5175249"},{"lat":"48.6875133","lon":"19.7581682"}]

2024-03-30 16:04:03.447 11525-12026     D  ### 데이터담기 시작 : 1711782243447
2024-03-30 16:04:03.448 11525-12026.    A  java_vm_ext.cc:591] JNI DETECTED ERROR IN APPLICATION: can't make objects of type test.BearAreaVo: 0x1311c6a0
                                                                                                    java_vm_ext.cc:591]     in call to AllocObject
                                                                                                    java_vm_ext.cc:591]     from java.lang.Object sun.misc.Unsafe.allocateInstance(java.lang.Class)
2024-03-30 16:04:03.658 11525-12026     A  runtime.cc:691] Runtime aborting...
                                                                                                    runtime.cc:691] Dumping all threads without mutator lock held
                                                                                                    runtime.cc:691] All threads:
                                                                                                    runtime.cc:691] DALVIK THREADS (114):
                                                                                                    runtime.cc:691] "main" prio=10 tid=1 Native
                                                                                                    runtime.cc:691]   | group="" sCount=1 ucsCount=0 flags=1 obj=0x7288bf68 self=0xb40000766332b000
                                                                                                    runtime.cc:691]   | sysTid=11525 nice=-10 cgrp=top-app sched=0/0 handle=0x7723c98500
                                                                                                    runtime.cc:691]   | state=S schedstat=( 3192259952 872834338 4533 ) utm=261 stm=57 core=3 HZ=100
                                                                                                    runtime.cc:691]   | stack=0x7fe353d000-0x7fe353f000 stackSize=8188KB
                                                                                                    runtime.cc:691]   | held mutexes=
                                                                                                    runtime.cc:691]   native: #00 pc 000911c0  /apex/com.android.runtime/lib64/bionic/libc.so (syscall+32) (BuildId: 02a91a85343debb2911714273ff2b670)
                                                                                                    runtime.cc:691]   native: #01 pc 00232858  /apex/com.android.art/lib64/libart.so (art::ConditionVariable::WaitHoldingLocks+140) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #02 pc 003deaf4  /apex/com.android.art/lib64/libart.so (art::::CheckJNI::CallMethodV +3024) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #03 pc 003ddefc  /apex/com.android.art/lib64/libart.so (art::::CheckJNI::CallObjectMethodV +72) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #04 pc 000e3994  /system/lib64/libandroid_runtime.so (_JNIEnv::CallObjectMethod+124) (BuildId: 0f2143911bbb9c33f3ed4f2893cb0014)
                                                                                                    runtime.cc:691]   native: #05 pc 00153f70  /system/lib64/libandroid_runtime.so (android::NativeDisplayEventReceiver::dispatchVsync+68) (BuildId: 0f2143911bbb9c33f3ed4f2893cb0014)
                                                                                                    runtime.cc:691]   native: #06 pc 000cba58  /system/lib64/libgui.so (android::DisplayEventDispatcher::handleEvent+280) (BuildId: 7e32b5e2b6d51b4a075d7f37c2ac8fc3)
                                                                                                    runtime.cc:691]   native: #07 pc 00018b70  /system/lib64/libutils.so (android::Looper::pollInner+1252) (BuildId: d0c24e3b7b6c7152eb82e77a5d2271e6)
                                                                                                    runtime.cc:691]   native: #08 pc 00018628  /system/lib64/libutils.so (android::Looper::pollOnce+124) (BuildId: d0c24e3b7b6c7152eb82e77a5d2271e6)
                                                                                                    runtime.cc:691]   native: #09 pc 0018f184  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce+48) (BuildId: 0f2143911bbb9c33f3ed4f2893cb0014)
                                                                                                    runtime.cc:691]   native: #10 pc 00355630  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #11 pc 0033eba4  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #12 pc 00512a24  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>+1976) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #13 pc 004962a4  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>+2092) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #14 pc 00357dd8  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #15 pc 0023a01c  /system/framework/framework.jar (android.os.MessageQueue.next)
                                                                                                    runtime.cc:691]   native: #16 pc 00371b14  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute +232) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #17 pc 005136f0  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>+5252) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #18 pc 00495e6c  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>+1012) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #19 pc 00357dd8  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #20 pc 00238f04  /system/framework/framework.jar (android.os.Looper.loopOnce)
2024-03-30 16:04:03.658 11525-12026 t.app.bear.bell         ddolcat.app.bear.bell                A  runtime.cc:691]   native: #21 pc 00371b14  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute +232) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #22 pc 005136f0  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>+5252) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #23 pc 004961dc  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>+1892) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #24 pc 00357dd8  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #25 pc 00239740  /system/framework/framework.jar (android.os.Looper.loop)
                                                                                                    runtime.cc:691]   native: #26 pc 00371b14  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute +232) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #27 pc 005136f0  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>+5252) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #28 pc 004961dc  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>+1892) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #29 pc 00357dd8  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #30 pc 001d2ecc  /system/framework/framework.jar (android.app.ActivityThread.main)
                                                                                                    runtime.cc:691]   native: #31 pc 00371b14  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute +232) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #32 pc 0037140c  /apex/com.android.art/lib64/libart.so (artQuickToInterpreterBridge+964) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #33 pc 00355768  /apex/com.android.art/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #34 pc 0033ee80  /apex/com.android.art/lib64/libart.so (art_quick_invoke_static_stub+640) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #35 pc 0037ff40  /apex/com.android.art/lib64/libart.so (_jobject* art::InvokeMethod<8>+1556) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #36 pc 0037f91c  /apex/com.android.art/lib64/libart.so (art::Method_invoke +32) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #37 pc 00355630  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #38 pc 0033eba4  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #39 pc 00512a24  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>+1976) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #40 pc 00495e6c  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>+1012) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #41 pc 00357dd8  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #42 pc 0026814c  /system/framework/framework.jar (com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run)
                                                                                                    runtime.cc:691]   native: #43 pc 00371b14  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute +232) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #44 pc 0037140c  /apex/com.android.art/lib64/libart.so (artQuickToInterpreterBridge+964) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   native: #45 pc 00355768  /apex/com.android.art/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 02bec5940be704b863f6514fc7d81c41)
                                                                                                    runtime.cc:691]   at android.os.MessageQueue.nativePollOnce(Native method)
2024-03-30 16:04:03.658 11525-12026 t.app.bear.bell         ddolcat.app.bear.bell                A  runtime.cc:691]   at android.os.MessageQueue.next(MessageQueue.java:335)
                                                                                                    runtime.cc:691]   at android.os.Looper.loopOnce(Looper.java:187)
                                                                                                    runtime.cc:691]   at android.os.Looper.loop(Looper.java:319)
                                                                                                    runtime.cc:691]   at android.app.ActivityThread.main(ActivityThread.java:8919)
                                                                                                    runtime.cc:691]   at java.lang.reflect.Method.invoke(Native method)
                                                                                                    runtime.cc:691]   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
                                                                                                    runtime.cc:691]   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
                                                                                                    runtime.cc:691] 
                                                                                                    runtime.cc:691] "FinalizerDaemon" prio=5 tid=10 Waiting
                                                                                                    runtime.cc:691]   | group="" sCount=1 ucsCount=0 flags=1 obj=0x12c006c0 self=0xb400007614cbe400
                                                                                                    runtime.cc:691]   | sysTid=11537 nice=4 cgrp=top-app sched=0/0 handle=0x761f943cb0
                                                                                                    runtime.cc:691]   | state=S schedstat=( 37284473 14547970 101 ) utm=3 stm=0 core=4 HZ=100
                                                                                                    runtime.cc:691]   | stack=0x761f840000-0x761f842000 stackSize=1039KB
                                                                                                    runtime.cc:691]   | held mutexes=

코드부터 하나씩 살펴본다.


작업중인 Gson 코드

private void makeJson( String result) {
        Gson gson = new Gson();
        try {
            Document document = Jsoup.parse(result);

            Element divTag3 = document.getElementById("bearArea");
            String jsonString2 = divTag3.text();
            Log.d(DefaultSettings.TAG, "### jsonString2 : " + jsonString2);

            Log.d(DefaultSettings.TAG, "### 데이터담기 시작 : " + System.currentTimeMillis());
            // BearAreaVo info = gson.fromJson(result, BearAreaVo.class);

            bearArea = gson.fromJson(jsonString2, BearAreaVo[].class);
            Log.d(DefaultSettings.TAG, "### 데이터담기 종료 : " + System.currentTimeMillis());

            //기본 조회 조건으로 데이터 조회
            setMapMarkerForTradeName();

            if (MapsActivity.this != null && !MapsActivity.this.isFinishing()) {
                //hideProgressDialog();
                closeProgressDialog();
                // new CustomDialog(MapsActivity.this);  //체크 다이얼로그 호출
            }

        }catch (Exception e){
//            e.printStackTrace();
            System.err.println(e.toString());
        }

    }

오류가 발생한 코드를 살펴보자. 오류가 발생한 코드 위치는 아래와 같다.

BearAreaVo[] bearArea = gson.fromJson(jsonString2, BearAreaVo[].class);

이전에는 정상적으로 동작하던 코드인데 오류가 발생한다.


BearAreaVo 클래스

package test.app.common;

import com.google.gson.annotations.SerializedName;

public class BearAreaVo {
    @SerializedName("lat")
    double latitude;

    @SerializedName("lon")
    double longitude;


    public BearAreaVo(double _longitude, double _latitude){
        this.longitude = _longitude;
        this.latitude = _latitude;
    }


    @Override
    public String toString() {
        return "BearAreaVo [ longitude=" + longitude + ", latitude=" + latitude + "]";
    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }

}

오류 해결을 위한 코드 삽질이 시작되었다.

List<BearAreaVo> bearArea = Collections.singletonList(gson.fromJson(jsonString2, BearAreaVo.class));

리스트 타입으로 변경 후 시도하였으나 동일한 오류가 발생되었다.

커스텀 gson을 생성하여 시도하였다.

    private Gson getCustomGson() {
        Map<Type, TypeAdapter<?>> adapterMap = new HashMap<>();
        adapterMap.put(String.class, new StringTypeAdapter());

        GsonBuilder builder = new GsonBuilder();

        for(Map.Entry<Type, TypeAdapter<?>> entry : adapterMap.entrySet()){
            builder.registerTypeAdapter(entry.getKey(), entry.getValue());
        }
        return builder.create();
    }

Gson gson = getCustomGson();

그러나 여전히 동일하게 오류가 발생하였다.

proguard-rules.pro 설정파일에 설정된 내용도 살펴보았다. -keep class sun.misc.Unsafe { *; } 에 빨간줄이 보인다. 이것때문이가?

# Gson specific classes
-dontwarn sun.misc.**
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }


# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }

gson 라이브러리 변경

as-is: implementation ‘com.squareup.retrofit2:converter-gson:2.0.2’

to-be: implementation ‘com.google.code.gson:gson:2.10.1’

라이브러리 변경 후 테스트를 하였다. 여전히 오류는 발생되었으나 해결방법을 알려주네???

com.google.gson.JsonIOException: Abstract classes can't be instantiated! Register an InstanceCreator or a TypeAdapter for this type. Class name: com.app.common.BearAreaVo                I  


해결방법

추상 클래스는 인스턴스화할 수 없다! 이 유형에 대해 InstanceCreator 또는 TypeAdapter를 등록해야한다.

ChatGPT에게 오류 해결방법을 물었다.

질문내용 : User
 com.google.gson.JsonIOException: Abstract classes can't be instantiated! Register an InstanceCreator or a TypeAdapter for this type. Class name: com.app.common.BearAreaVo  라는 오류가 발생되었어,  어떻게 해야해?

답변은 아주 훌륭했다.

이 오류는 Gson 라이브러리를 사용할 때 발생하는 것으로 보입니다. 이 오류는 ddolcat.app.bear.bell.common.BearAreaVo 클래스가 추상 클래스이기 때문에 인스턴스화할 수 없다는 것을 나타냅니다. Gson은 추상 클래스를 직접 인스턴스화할 수 없으므로 이 클래스에 대한 인스턴스 생성자(InstanceCreator) 또는 타입 어댑터(TypeAdapter)를 등록해야 합니다.

해결 방법으로는 두 가지 옵션이 있습니다:

InstanceCreator 등록: Gson에게 해당 추상 클래스의 인스턴스를 만들기 위한 방법을 알려줍니다. 예를 들어, InstanceCreator 인터페이스를 구현하여 Gson에게 어떻게 인스턴스를 만들어야 하는지 알려줄 수 있습니다.

TypeAdapter 등록: Gson에게 해당 클래스에 대한 직렬화 및 역직렬화를 처리하는 방법을 제공합니다. 이를 통해 Gson이 추상 클래스를 직접 인스턴스화하지 않고도 객체를 생성할 수 있습니다.

어떤 방법을 선택할지는 코드와 요구 사항에 따라 다를 수 있습니다. 일반적으로는 TypeAdapter를 구현하는 것이 더 일반적인 방법입니다.

간단한 예제로 두 가지 방법을 보여드리겠습니다.

InstanceCreator 사용:
import com.google.gson.InstanceCreator;
import java.lang.reflect.Type;

public class BearAreaVoInstanceCreator implements InstanceCreator<BearAreaVo> {
    public BearAreaVo createInstance(Type type) {
        // 인스턴스를 생성하는 코드를 여기에 작성합니다.
        return new BearAreaVo();
    }
}

그런 다음 Gson 빌더에 이 InstanceCreator를 등록합니다:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(BearAreaVo.class, new BearAreaVoInstanceCreator())
    .create();

TypeAdapter 사용:

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;

public class BearAreaVoTypeAdapter extends TypeAdapter<BearAreaVo> {
    @Override
    public void write(JsonWriter out, BearAreaVo value) throws IOException {
        // BearAreaVo 객체를 JSON으로 직렬화하는 코드를 작성합니다.
    }

    @Override
    public BearAreaVo read(JsonReader in) throws IOException {
        // JSON을 BearAreaVo 객체로 역직렬화하는 코드를 작성합니다.
        return null;
    }
}

그런 다음 Gson 빌더에 이 TypeAdapter를 등록합니다:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(BearAreaVo.class, new BearAreaVoTypeAdapter())
    .create();

어떤 방법을 선택할지는 사용 중인 라이브러리와 코드의 구조에 따라 다를 수 있습니다.

좀 더 자세히 물었다. TypeAdapter 사용하려고 해.. BearAreaVo 클래스 전체 코드를 던져주었다.

결과는 놀라웠다. ㅎㅎㅎ

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;

public class BearAreaVoTypeAdapter extends TypeAdapter<BearAreaVo> {
    @Override
    public void write(JsonWriter out, BearAreaVo value) throws IOException {
        out.beginObject();
        out.name("lat").value(value.getLatitude());
        out.name("lon").value(value.getLongitude());
        out.endObject();
    }

    @Override
    public BearAreaVo read(JsonReader in) throws IOException {
        double latitude = 0.0;
        double longitude = 0.0;

        in.beginObject();
        while (in.hasNext()) {
            String name = in.nextName();
            if (name.equals("lat")) {
                latitude = in.nextDouble();
            } else if (name.equals("lon")) {
                longitude = in.nextDouble();
            } else {
                in.skipValue(); // Unexpected property, ignore it
            }
        }
        in.endObject();

        return new BearAreaVo(longitude, latitude);
    }
}



import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

// ...

Gson gson = new GsonBuilder()
    .registerTypeAdapter(BearAreaVo.class, new BearAreaVoTypeAdapter())
    .create();

위의 코드는 BearAreaVo 객체를 JSON으로 직렬화하고 JSON을 BearAreaVo 객체로 역직렬화할 수 있도록 도와줍니다.

ChatGPT가 만들어준 코드로 테스트를 하였으나 아래와 같은 오류가 발생되었다.


com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $오류 해결

다시 질문 :
너가 만들어준 코드에 아래와 같은 오류가 발생했어
어떻게 해야해?
 com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
ChatGPT 답변:
해당 오류는 Gson이 JSON을 파싱하는 도중에 예상하지 못한 형식의 데이터를 만났을 때 발생합니다. 오류 메시지를 살펴보면 "Expected BEGIN_OBJECT but was BEGIN_ARRAY"라고 되어 있습니다. 이는 Gson이 객체(Object)를 예상했지만 배열(Array)이 나왔다는 것을 의미합니다.

이 문제를 해결하려면 해당 JSON의 구조를 확인하고, 코드에 맞게 수정해야 합니다. 예를 들어, JSON 데이터가 객체(Object) 대신 배열(Array) 형태로 제공되는 경우가 있습니다. 이런 경우에는 JSON 데이터를 어떻게 제공받고 있는지 확인하고, 그에 맞게 코드를 수정해야 합니다.

만약 코드에서 JSON 데이터를 제공받는 부분을 알려주신다면, 더 자세한 도움을 드릴 수 있을 것입니다. JSON 데이터와 함께 어떻게 파싱하고 있는지 코드 일부를 공유해 주시면 됩니다.

나는 json 데이터를 chatGPT에게 던져줬다.

json 데이터는 아래와 같아
[{"lat":"49.254381","lon":"-122.8183091"},{"lat":"49.2958984","lon":"-122.7043395"},{"lat":"49.3578478","lon":"-123.0274911"},{"lat":"49.3342397","lon":"-123.0012486"},{"lat":"49.3475493","lon":"-122.8686121"},{"lat":"49.3199479","lon":"-122.8940357"},{"lat":"49.1807551","lon":"-122.7629478"},{"lat":"49.1912566","lon":"-122.7316538"},{"lat":"49.395506","lon":"-123.201689"},{"lat":"49.2459918","lon":"-122.5442593"},{"lat":"49.3064387","lon":"-123.0020362"},{"lat":"51.1841171","lon":"-115.5847927"},{"lat":"51.1791155","lon":"-115.6099708"},{"lat":"51.1719064","lon":"-115.4693033"},{"lat":"51.180894","lon":"-115.583712"},{"lat":"50.089398","lon":"-95.321851"},{"lat":"49.821259","lon":"-95.481628"},{"lat":"52.2901734","lon":"-119.6858619"},{"lat":"51.0497666","lon":"-123.0886179"},{"lat":"52.5954402","lon":"-126.0732929"},{"lat":"64.0686028","lon":"-147.5051942"},{"lat":"50.059988","lon":"-122.955940"},{"lat":"49.5592368","lon":"-125.403021"},{"lat":"57.7899846","lon":"-93.2418164"},{"lat":"51.3705027","lon":"-127.1028468"},{"lat":"48.7919313","lon":"-125.1585477"},{"lat":"50.8661206","lon":"-125.9815131"},{"lat":"52.8812158","lon":"-127.7398788"},{"lat":"49.232985","lon":"-122.933735"},{"lat":"51.029237","lon":"-115.258111"},{"lat":"51.496149","lon":"-115.928038"},{"lat":"52.871658","lon":"-117.954220"},{"lat":"48.9489724","lon":"19.5175249"},{"lat":"48.6875133","lon":"19.7581682"}]

ChatGPT 답변:

주어진 JSON 데이터는 배열(Array) 형태로 되어 있습니다. 각 요소는 위도(lat)와 경도(lon)를 나타내는 객체(Object)입니다. 이러한 구조에 맞게 Gson을 사용하여 파싱할 수 있도록 코드를 수정해야 합니다.

이를 위해 먼저 Gson을 사용하여 JSON 배열을 Java 객체로 변환할 때 리스트(List) 형태로 받아와야 합니다. 그런 다음 각 객체를 BearAreaVo 클래스의 인스턴스로 매핑해야 합니다.

아래는 주어진 JSON 데이터를 파싱하여 BearAreaVo 객체의 리스트로 변환하는 코드 예제입니다:

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        String json = "[{\"lat\":\"49.254381\",\"lon\":\"-122.8183091\"},{\"lat\":\"49.2958984\",\"lon\":\"-122.7043395\"},{\"lat\":\"49.3578478\",\"lon\":\"-123.0274911\"},{\"lat\":\"49.3342397\",\"lon\":\"-123.0012486\"},{\"lat\":\"49.3475493\",\"lon\":\"-122.8686121\"},{\"lat\":\"49.3199479\",\"lon\":\"-122.8940357\"},{\"lat\":\"49.1807551\",\"lon\":\"-122.7629478\"},{\"lat\":\"49.1912566\",\"lon\":\"-122.7316538\"},{\"lat\":\"49.395506\",\"lon\":\"-123.201689\"},{\"lat\":\"49.2459918\",\"lon\":\"-122.5442593\"},{\"lat\":\"49.3064387\",\"lon\":\"-123.0020362\"},{\"lat\":\"51.1841171\",\"lon\":\"-115.5847927\"},{\"lat\":\"51.1791155\",\"lon\":\"-115.6099708\"},{\"lat\":\"51.1719064\",\"lon\":\"-115.4693033\"},{\"lat\":\"51.180894\",\"lon\":\"-115.583712\"},{\"lat\":\"50.089398\",\"lon\":\"-95.321851\"},{\"lat\":\"49.821259\",\"lon\":\"-95.481628\"},{\"lat\":\"52.2901734\",\"lon\":\"-119.6858619\"},{\"lat\":\"51.0497666\",\"lon\":\"-123.0886179\"},{\"lat\":\"52.5954402\",\"lon\":\"-126.0732929\"},{\"lat\":\"64.0686028\",\"lon\":\"-147.5051942\"},{\"lat\":\"50.059988\",\"lon\":\"-122.955940\"},{\"lat\":\"49.5592368\",\"lon\":\"-125.403021\"},{\"lat\":\"57.7899846\",\"lon\":\"-93.2418164\"},{\"lat\":\"51.3705027\",\"lon\":\"-127.1028468\"},{\"lat\":\"48.7919313\",\"lon\":\"-125.1585477\"},{\"lat\":\"50.8661206\",\"lon\":\"-125.9815131\"},{\"lat\":\"52.8812158\",\"lon\":\"-127.7398788\"},{\"lat\":\"49.232985\",\"lon\":\"-122.933735\"},{\"lat\":\"51.029237\",\"lon\":\"-115.258111\"},{\"lat\":\"51.496149\",\"lon\":\"-115.928038\"},{\"lat\":\"52.871658\",\"lon\":\"-117.954220\"},{\"lat\":\"48.9489724\",\"lon\":\"19.5175249\"},{\"lat\":\"48.6875133\",\"lon\":\"19.7581682\"}]";

        // JSON을 List<BearAreaVo>로 변환
        Type listType = new TypeToken<List<BearAreaVo>>(){}.getType();
        List<BearAreaVo> bearAreaList = new Gson().fromJson(json, listType);

        // 결과 확인
        for (BearAreaVo bearArea : bearAreaList) {
            System.out.println(bearArea);
        }
    }
}

위의 코드에서는 먼저 JSON 데이터를 List<BearAreaVo> 형태로 변환하기 위해 TypeToken을 사용합니다. 그런 다음 Gson의 fromJson 메서드를 사용하여 JSON 데이터를 리스트로 변환합니다. 마지막으로 변환된 리스트를 출력하여 확인합니다.

이제 주어진 JSON 데이터를 파싱하여 사용할 수 있게 되었습니다.

이번에 또 다른 오류가 발생되었고, 다시 물었다.

java.lang.IllegalStateException: TypeToken must be created with a type argument: new TypeToken<…>() {}; When using code shrinkers (ProGuard, R8, …) make sure that generic signatures are preserved.

ChatGPT 답변:

이 오류는 Gson의 TypeToken을 사용할 때 발생합니다. 이 오류는 일반적으로 코드 축소기(ProGuard, R8 등)에서 발생하는 경우가 많습니다. 코드 축소기는 제네릭 시그니처를 보존하지 않을 때 이러한 종류의 문제가 발생할 수 있습니다.

이 문제를 해결하려면 코드 축소기 설정에서 제네릭 시그니처를 보존하도록 설정해야 합니다. 예를 들어 ProGuard를 사용하는 경우 proguard-rules.pro 파일에 다음과 같은 설정을 추가할 수 있습니다:
-keepattributes Signature

또는 R8을 사용하는 경우 proguard-rules.pro 파일에 다음과 같은 설정을 추가합니다:

-keep,allowobfuscation class * {
    <fields>;
    <methods>;
}

이렇게 하면 제네릭 시그니처가 보존되어 Gson의 TypeToken을 올바르게 사용할 수 있게 됩니다.

만약 위의 방법으로도 문제가 해결되지 않는다면, 코드 축소기 설정을 자세히 살펴보고 해당 설정을 수정해야 할 수도 있습니다. 그리고 이후에는 Gson의 TypeToken을 사용하여 다시 코드를 작성하면 됩니다.

삽질 시간이 단축되는 구나!!! 고맙다 쳇GPT

오류는 해결되었다.!!!

참 개발하기 편한 세상이 오는구나!!

[연관 자료]

https://github.com/google/gson/issues/817

https://stackoverflow.com/questions/36117269/cannot-deserialize-object-with-gson-lib

https://stackoverflow.com/questions/24713488/java-lang-nosuchmethoderror-sun-misc-unsafe-with-external-jar-on-android

https://rangken.github.io/blog/2015/sun.misc.unSafe/

error: Content is protected !!