【Gson三】Gson解析{ダタ}

9723 ワード


どのようにして以下の簡単なJSON文字列をJavaのPOJOオブジェクトに逆順序化しますか?
{"data":{"IM":["MSN","QQ","Gtalk"]}}
 
以下のPOJO類Modelでは正しい解析ができません。
 
import com.google.gson.Gson;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Model {
    private Map<String, Map<String, List<String>>> data;

    public Map<String, Map<String, List<String>>> getData() {
        return data;
    }

    public void setData(Map<String, Map<String, List<String>>> data) {
        this.data = data;
    }
}

public class ModelTest {
    public static void main(String[] args) {
        List<String> ims = new ArrayList<String>();
        ims.add("MSN");
        ims.add("QQ");
        ims.add("Gtalk");
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        map.put("IM", ims);

        Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
        dataMap.put("data", map);
        String str = new Gson().toJson(dataMap);
        System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/
        Model m = new Gson().fromJson(str, Model.class);
    }
}
 
異常情報:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 17
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
	at com.google.gson.Gson.fromJson(Gson.java:803)
	at com.google.gson.Gson.fromJson(Gson.java:768)
	at com.google.gson.Gson.fromJson(Gson.java:717)
	at com.google.gson.Gson.fromJson(Gson.java:689)
	at gson.test4.ModelTest.main(ModelTest.java:35)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 17
	at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:338)
	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:172)
	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
	at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:187)
	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
	... 10 more
 
この問題はどう解決しますか?
 
コードをよく見たら、エラーは正常です。コードの中では、strはdataMapから順番に並べられています。これをdataMapから変換したJSONストリップの逆シーケンスをModelタイプとしています。間違いは必然です。
String str = new Gson().toJson(dataMap);
Model m = new Gson().fromJson(str, Model.class)
ModelオブジェクトがJSONの列になっているデータはどのようなものですか?
{"data":{"data":{"IM":["MSN","QQ","Gtalk"]}}}
 
この場合、解決の方法は2つあります。
 
1.以下のJSONストリングに対して、対応するデータ構造はMap<String、Map<String、List<String>であり、これを直接にMap<String、Map<String、List<String>に変えてもいいです。例えば、以下のコードです。
{"data":{"IM":["MSN","QQ","Gtalk"]}}
それをMapに変換します。
 
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Model {
    private Map<String, Map<String, List<String>>> data;

    public Map<String, Map<String, List<String>>> getData() {
        return data;
    }

    public void setData(Map<String, Map<String, List<String>>> data) {
        this.data = data;
    }
}

public class ModelTest {
    public static void main(String[] args) {
        List<String> ims = new ArrayList<String>();
        ims.add("MSN");
        ims.add("QQ");
        ims.add("Gtalk");
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        map.put("IM", ims);

        Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
        dataMap.put("data", map);
        String str = new Gson().toJson(dataMap);
        System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/

        Type type = new TypeToken<Map<String, Map<String, List<String>>>>(){}.getType();

        dataMap = new Gson().fromJson(str, type);
        ims= dataMap.get("data").get("IM");
        for(int i = 0;  i< ims.size(); i++) {
            System.out.println(ims.get(i));
        }
    }
}
 
2.Modelのデータ構造を再定義し、それに含まれるデータの種類はprvate Map<String、List<String>dataであるべきです。コードは以下の通りです。この時は正確に解析できます。
 
 
 
import com.google.gson.Gson;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Model {
    private Map<String, List<String>> data;

    public Map<String, List<String>> getData() {
        return data;
    }

    public void setData(Map<String, List<String>> data) {
        this.data = data;
    }
}

public class ModelTest {
    public static void main(String[] args) {
        List<String> ims = new ArrayList<String>();
        ims.add("MSN");
        ims.add("QQ");
        ims.add("Gtalk");
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        map.put("IM", ims);

        Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
        dataMap.put("data", map);
        String str = new Gson().toJson(dataMap);
        System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/

        Model m = new Gson().fromJson(str, Model.class);
        System.out.println(m!=null);
    }
}
 
 3.Typeを使わずに直接Map.classを使う場合、範型は使われませんが、正しい出力が得られます。なぜですか?
 
import com.google.gson.Gson;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Model {
    private Map<String, Map<String, List<String>>> data;

    public Map<String, Map<String, List<String>>> getData() {
        return data;
    }

    public void setData(Map<String, Map<String, List<String>>> data) {
        this.data = data;
    }
}

public class ModelTest {
    public static void main(String[] args) {
        List<String> ims = new ArrayList<String>();
        ims.add("MSN");
        ims.add("QQ");
        ims.add("Gtalk");
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        map.put("IM", ims);

        Map<String, Map<String, List<String>>> dataMap = new HashMap<String, Map<String, List<String>>>();
        dataMap.put("data", map);
        String str = new Gson().toJson(dataMap);
        System.out.println(str);/*{"data":{"IM":["MSN","QQ","Gtalk"]}}*/

        //Type type = new TypeToken<Map<String, Map<String, List<String>>>>(){}.getType();
        //Map<String, Map<String, List<String>>> t = null;
        dataMap = new Gson().fromJson(str, Map.class); //   Type    ,       ?
        ims= dataMap.get("data").get("IM");
        for(int i = 0;  i< ims.size(); i++) {
            System.out.println(ims.get(i));
        }
    }
}