Google Gson - सूची का वर्णन <वर्ग> वस्तु? (सामान्य प्रकार)


441

मैं Google Gson के माध्यम से एक सूची ऑब्जेक्ट को स्थानांतरित करना चाहता हूं, लेकिन मुझे नहीं पता कि जेनेरिक प्रकारों को कैसे निष्क्रिय करना है।

मैं किसकी तलाश के बाद की कोशिश की इस (BalusC का जवाब):

MyClass mc = new Gson().fromJson(result, new List<MyClass>(){}.getClass());

लेकिन तब मुझे यह कहते हुए ग्रहण में एक त्रुटि मिलती है "टाइप नई सूची () {} को विरासत में मिली अमूर्त पद्धति को लागू करना चाहिए ..." और अगर मैं एक त्वरित फिक्स का उपयोग करता हूं तो मुझे 20 से अधिक विधि स्टब्स का एक राक्षस मिलता है।

मुझे पूरा यकीन है कि एक आसान उपाय है, लेकिन मैं इसे खोजने में असमर्थ हूं!

संपादित करें:

अब मेरे पास है

Type listType = new TypeToken<List<MyClass>>()
                {
                }.getType();

MyClass mc = new Gson().fromJson(result, listType);

हालाँकि, मुझे "fromJson" लाइन में निम्न अपवाद मिलते हैं:

java.lang.NullPointerException
at org.apache.harmony.luni.lang.reflect.ListOfTypes.length(ListOfTypes.java:47)
at org.apache.harmony.luni.lang.reflect.ImplForType.toString(ImplForType.java:83)
at java.lang.StringBuilder.append(StringBuilder.java:203)
at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:56)
at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:88)
at com.google.gson.JsonDeserializationVisitor.visitUsingCustomHandler(JsonDeserializationVisitor.java:76)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:106)
at com.google.gson.JsonDeserializationContextDefault.fromJsonArray(JsonDeserializationContextDefault.java:64)
at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:49)
at com.google.gson.Gson.fromJson(Gson.java:568)
at com.google.gson.Gson.fromJson(Gson.java:515)
at com.google.gson.Gson.fromJson(Gson.java:484)
at com.google.gson.Gson.fromJson(Gson.java:434)

मैं कर पकड़ JsonParseExceptions और "परिणाम" नल नहीं है।

मैंने डीबगर के साथ सूची टाइप की जाँच की और निम्नलिखित मिला:

  • सूची प्रकार
    • args = ListOfTypes
      • सूची = अशक्त
      • हल किया गया = टाइप [1]
    • लोडर = PathClassLoader
    • ownerType0 = null
    • ownerTypeRes = null
    • rawType = क्लास (java.util.ArrayList)
    • rawTypeName = "java.util.ArrayList"

तो ऐसा लगता है कि "getClass" मंगलाचरण ठीक से काम नहीं किया। कोई सुझाव...?

Edit2: मैं Gson उपयोगकर्ता गाइड पर जाँच कर रहा हूँ । इसमें एक रनटाइम अपवाद का उल्लेख किया गया है जो जेनसन को एक सामान्य प्रकार को पार्स करने के दौरान होना चाहिए। मैंने इसे "गलत" किया (ऊपर नहीं दिखाया गया), उदाहरण के रूप में, लेकिन उस अपवाद को बिल्कुल नहीं मिला। इसलिए मैंने सुझाए गए उपयोगकर्ता गाइड के अनुसार क्रमिकता को बदल दिया। हालांकि मदद नहीं की।

Edit3: हल, मेरा जवाब नीचे देखें।


1
आपके द्वारा बताया गया उत्तर, उपयोग करता है TokenType। क्या आपने इस तरह से कोशिश की है?
निशांत

बस एक संकेत के रूप में एक ही जवाब मिला। अगली बार मैं उदाहरण को करीब से देखूंगा। ;)
जेलिफ़िश

क्या आप टाइप टोकन में सूची के कार्यान्वयन का प्रयास कर सकते हैं? चूंकि आपकी कच्ची प्रकार सरणी सूची है, इसलिए आपको सरणी सूची की कोशिश करनी चाहिए।
अप्रयुक्त_एक्सपेप्शन

जवाबों:


954

जेनेरिक संग्रह का वर्णन करने की विधि:

import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;

...

Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> yourClassList = new Gson().fromJson(jsonArray, listType);

चूंकि टिप्पणियों में कई लोगों ने इसका उल्लेख किया है, इसलिए यहां इस बात का स्पष्टीकरण दिया गया है कि TypeTokenकक्षा का उपयोग कैसे किया जा रहा है। निर्माण new TypeToken<...>() {}.getType()एक संकलित वस्तु में एक संकलन समय प्रकार ( <और के बीच >) को पकड़ता है java.lang.reflect.Type। एक Classवस्तु के विपरीत , जो केवल एक कच्चे (मिटाए गए) प्रकार का प्रतिनिधित्व कर सकती हैType प्रतिनिधित्व कर सकती है ऑब्जेक्ट जावा भाषा में किसी भी प्रकार का प्रतिनिधित्व कर सकता है, जिसमें एक सामान्य प्रकार का एक मानकीकृत तात्कालिकता भी शामिल है।

TypeTokenक्योंकि आप इसे सीधे निर्माण करने के लिए नहीं करना पड़ेगा वर्ग ही है, एक सार्वजनिक निर्माता नहीं है। इसके बजाय, आप हमेशा एक अनाम उपवर्ग का निर्माण करते हैं (इसलिए {}, जो इस अभिव्यक्ति का एक आवश्यक हिस्सा है)।

प्रकार के क्षरण के कारण, TypeTokenवर्ग केवल उन प्रकारों को पकड़ने में सक्षम है जो पूरी तरह से संकलन समय पर ज्ञात हैं। (अर्थात, आप new TypeToken<List<T>>() {}.getType()एक प्रकार के पैरामीटर के लिए नहीं कर सकते T।)

अधिक जानकारी के लिए, TypeTokenवर्ग के लिए दस्तावेज़ देखें ।


31
GSON के नए संस्करणों में TypeToken contructor सार्वजनिक नहीं है, इसलिए यहां आपको कंस्ट्रक्टर दिखाई नहीं देता त्रुटि दिखाई देती है। इस मामले में आपको क्या करना है?
पाब्लो

8
GSON (2.2.4) के वास्तविक संस्करण का उपयोग करना यह फिर से काम करता है। आप यहां कंस्ट्रक्टर को एक्सेस कर सकते हैं।

मेरी json ऑब्जेक्ट किसी ऑब्जेक्ट से शुरू होती है, फिर उस ऑब्जेक्ट की एक सरणी होती है, जिसे मैं चाहता हूं { "myObjectArray":[ {....} , {....} , {....} ] }, मैंने इसके लिए मॉडल फ़ाइल बनाई है, मुझे {....}यह सामान्य संग्रह कोड कैसे मिलता है मानने के लिए नहीं कि मेरा रूट एलीमेंट एक नई नेस्टेड ऑब्जेक्ट फ़ाइल बनाने के बिना एक सरणी है
CQM

7
निम्नलिखित आयात की आवश्यकता है --- आयात java.lang.reflect.Type; आयात com.google.gson.reflect.TypeToken
उमर सलीम

4
यह अच्छा है अगर YourClass कोड में तय किया गया है। अगर क्लास रनटाइम पर आती है तो क्या होगा?
jasxir

273

एक और तरीका है एक सरणी को एक प्रकार के रूप में उपयोग करना

MyClass[] mcArray = gson.fromJson(jsonString, MyClass[].class);

इस तरह आप टाइप ऑब्जेक्ट के साथ सभी परेशानी से बचते हैं, और अगर आपको वास्तव में एक सूची की आवश्यकता है, तो आप हमेशा सरणी को एक सूची में बदल सकते हैं:

List<MyClass> mcList = Arrays.asList(mcArray);

IMHO यह बहुत अधिक पठनीय है।

और इसे वास्तविक सूची बनाने के लिए (जिसे संशोधित किया जा सकता है, सीमाएँ देखें Arrays.asList()) तो बस निम्नलिखित करें:

List<MyClass> mcList = new ArrayList<>(Arrays.asList(mcArray));

4
यह महान है! मैं इसे प्रतिबिंब के साथ कैसे उपयोग कर सकता हूं? मैं MyClassमूल्य नहीं जानता और इसे गतिशील रूप से परिभाषित किया जाएगा!
अमीन श ०

1
नोट: इस के साथ, सावधान रहें कि mcList एक पूर्ण सूची नहीं है। बहुत सी चीजें काम नहीं करेंगी।
njzk2

4
जेनरिक के साथ इसका उपयोग कैसे करें? T[] yourClassList = gson.fromJson(message, T[].class);// टाइप वेरिएबल से चयन नहीं कर सकता है
Pawel Cioch

2
उस टिप्पणी के समय @MateusViccari, mcListइस उत्तर में केवल कॉल का परिणाम था Arrays.asList। यह विधि एक सूची देती है, जिस पर यदि सभी वैकल्पिक तरीकों को लागू नहीं किया जाता है और अपवादों को फेंक दिया जाता है। उदाहरण के लिए, आप उस सूची में कोई तत्व नहीं जोड़ सकते। जैसा कि बाद के संपादन से पता चलता है, Arrays.asListसीमाएँ हैं, और इसे वास्तविक में लपेटने से ArrayListआपको एक सूची मिल सकती है जो कई मामलों में अधिक उपयोगी है।
njzk2

2
यदि आपको एक मनमाना तत्व प्रकार के लिए रनटाइम पर एक सरणी प्रकार का निर्माण करने की आवश्यकता है, तो आप डेविड वुड के उत्तरArray.newInstance(clazz, 0).getClass() में वर्णित अनुसार उपयोग कर सकते हैं ।
डैनियल प्राइडेन

31

इस पोस्ट को देखें। जीएसओएन के लिए तर्क के रूप में जावा टाइप जेनेरिक

मेरे पास इसके लिए बेहतर समाधान है। यहां लिस्ट के लिए रैपर क्लास है ताकि रैपर बिल्कुल उसी तरह की लिस्ट को स्टोर कर सके।

public class ListOfJson<T> implements ParameterizedType
{
  private Class<?> wrapped;

  public ListOfJson(Class<T> wrapper)
  {
    this.wrapped = wrapper;
  }

  @Override
  public Type[] getActualTypeArguments()
  {
      return new Type[] { wrapped };
  }

  @Override
  public Type getRawType()
  {
    return List.class;
  }

  @Override
  public Type getOwnerType()
  {
    return null;
  }
}

और फिर, कोड सरल हो सकता है:

public static <T> List<T> toList(String json, Class<T> typeClass)
{
    return sGson.fromJson(json, new ListOfJson<T>(typeClass));
}

क्या है mEntity.rulePattern?
अल लेलोपथ

यह परीक्षण के लिए सिर्फ एक नमूना वस्तु है। आपको इसकी परवाह करने की आवश्यकता नहीं है। उपयोग toList विधि और सब कुछ अच्छी तरह से चला जाता है।
हैपरियर

@ हैप्पीयर मैं इस Gson को लागू करने की कोशिश कर रहा हूँ 2.8.2 और यह काम नहीं कर रहा है। किसी भी मौका stackoverflow.com/questions/50743932/… आप देख सकते हैं और मुझे बता सकते हैं कि मैं क्या याद कर रहा हूँ
प्रवीण

1
@Praveen मैंने इस तरह से 2.8.2 में कोशिश की है, यह मूल के रूप में काम करता है।
हैपनियर

31

चूंकि Gson 2.8, हम जैसे उपयोग फ़ंक्शन बना सकते हैं

public <T> List<T> getList(String jsonArray, Class<T> clazz) {
    Type typeOfT = TypeToken.getParameterized(List.class, clazz).getType();
    return new Gson().fromJson(jsonArray, typeOfT);
}

उदाहरण का उपयोग कर

String jsonArray = ...
List<User> user = getList(jsonArray, User.class);

2
TypeToken#getParameterizedएक बेहतर तरीका है तो एक अनाम उपवर्ग के साथ हैक
निकोले कुलचेंको

यह स्वीकृत उत्तर होना चाहिए; कम से कम नए संस्करणों के लिए
ccpizza

2
यह एकदम सही जवाब है। मेरी समस्या का समाधान करता है।
डॉन जूल

मैंने आपकी विधि "जैसा है" को कॉपी किया है और यह काम नहीं करता है: कंपाइलर कहता है "विधि getParameterized (क्लास <सूची>, क्लास <टी>) टाइप टाइपेन के लिए अपरिभाषित है"। मैंने अपने गसन संस्करण (2.8.0) और दस्तावेज़ीकरण दोनों की जाँच की और इस तरफ सब कुछ ठीक है ... मैंने @ हेल्पियर समाधान का उपयोग करके समाप्त किया जो ठीक काम करता है
लेग्यूमिनेटर

@leguminator क्या आपने टाइपटोकन को आयात किया है? और आप जावा या कोटलिन का उपयोग कर रहे हैं। मैं फिर से परीक्षण करने की कोशिश करूंगा
फान वान लिन्ह

26

Wep, उसी परिणाम को प्राप्त करने का एक और तरीका। हम इसका उपयोग इसकी पठनीयता के लिए करते हैं।

इसके बजाय इस कठिन वाक्य को पढ़ने के लिए:

Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> list = new Gson().fromJson(jsonArray, listType);

एक खाली वर्ग बनाएं जो आपकी वस्तु की सूची का विस्तार करे:

public class YourClassList extends ArrayList<YourClass> {}

और JSON को पार्स करते समय इसका उपयोग करें:

List<YourClass> list = new Gson().fromJson(jsonArray, YourClassList.class);

9

कोटलिन के लिए बस:

import java.lang.reflect.Type
import com.google.gson.reflect.TypeToken
...
val type = object : TypeToken<List<T>>() {}.type

या, यहाँ एक उपयोगी कार्य है:

fun <T> typeOfList(): Type {
    return object : TypeToken<List<T>>() {}.type
}

फिर, उपयोग करने के लिए:

val type = typeOfList<YourMagicObject>()

मैंने आपके कोड का उपयोग इस प्रकार के फ़ंक्शन को बनाने के लिए किया है: inline fun <reified T> buildType() = object : TypeToken<T>() {}.type!!और प्रकार के साथ इसे कॉल करें:buildType<List<YourMagicObject>>()
coffeemakr

@coffeemakr आपको यहां पर संशोधित प्रकारों की आवश्यकता नहीं है।
चाड बिंघम

ओह। लेकिन आप ArrayList के टाइप टोकन क्यों बनाते हैं buildTypeऔर जेनेरिक प्रकार के साथ फ़ंक्शन को भी कहते हैं? क्या यह एक टाइपो है? - इससे ArrayList <ArrayList <YourMagicObject >>
coffeemakr

@coffeemakr आह, हाँ। टाइपो
चाड बिंगहैम

7
public static final <T> List<T> getList(final Class<T[]> clazz, final String json)
{
    final T[] jsonToObject = new Gson().fromJson(json, clazz);

    return Arrays.asList(jsonToObject);
}

उदाहरण:

getList(MyClass[].class, "[{...}]");

अच्छा था। लेकिन यह DevNGदो साल पहले लिखे गए उत्तर के ऊपर डुप्लिकेट है : stackoverflow.com/a/17300003/1339923 (और इस दृष्टिकोण के लिए जवाब का जवाब पढ़ें)
लेम्बर्ट

6

जैसा कि यह मेरे मूल प्रश्न का उत्तर देता है, मैंने doc_180 के उत्तर को स्वीकार कर लिया है, लेकिन यदि कोई फिर से इस समस्या में भाग लेता है, तो मैं अपने प्रश्न के दूसरे भाग का उत्तर दूंगा:

NullPointerError मैंने बताया कि सूची के साथ ही नहीं, बल्कि इसकी सामग्री के साथ कुछ भी नहीं था!

"MyClass" वर्ग में "कोई args" निर्माता नहीं था, और न ही इसका सुपरक्लास एक था। एक बार जब मैंने एक सरल "MyClass ()" कंस्ट्रक्टर को MyClass और इसके सुपरक्लास में शामिल किया, तो सब कुछ ठीक काम किया, जिसमें सूची क्रमांकन और डीरियलाइज़ेशन शामिल है जैसा कि doc_180 द्वारा सुझाया गया है।


1
यदि आपके पास अमूर्त वर्गों की सूची है तो आपको वही त्रुटि मिलेगी। मुझे लगता है कि यह जीएसओएन का सामान्य त्रुटि संदेश "तत्काल वर्ग के लिए असमर्थ" है।
ड्रू

एक निर्माता को जोड़ने के बारे में टिप ने मुझे यह महसूस करने में मदद की कि मेरे पास सभी अशक्त-मूल्य क्यों हैं। मैंने अपने JSON-string में "To" और "From" जैसे फ़ील्ड नाम थे, लेकिन मेरी वस्तु में संबंधित फ़ील्ड "से" और "से" निचले मामले में थे, इसलिए उन्हें छोड़ दिया गया
Rune

4

यहां एक समाधान है जो गतिशील रूप से परिभाषित प्रकार के साथ काम करता है। ट्रिक Array.newInstance () का उपयोग करके उचित प्रकार की सरणी बना रही है।

    public static <T> List<T> fromJsonList(String json, Class<T> clazz) {
    Object [] array = (Object[])java.lang.reflect.Array.newInstance(clazz, 0);
    array = gson.fromJson(json, array.getClass());
    List<T> list = new ArrayList<T>();
    for (int i=0 ; i<array.length ; i++)
        list.add(clazz.cast(array[i]));
    return list; 
}

यह उत्तर बेहतर होगा यदि आप class.cast()कास्टिंग के कारण होने वाली अनियंत्रित चेतावनी से बचते थे (T)। या, बेहतर अभी तक, कास्टिंग से परेशान न हों और Arrays.asList()किसी सरणी से ए में परिवर्तित होने के लिए कुछ का उपयोग करें List<T>। इसके अलावा, लंबाई को पास करने की कोई आवश्यकता नहीं है Array.newInstance()- आकार शून्य की एक सरणी को कॉल करने के लिए पर्याप्त अच्छा होगा getClass()
डैनियल प्राइडेन

सुझाव के लिए धन्यवाद, मैंने आपके सुझाए बदलाव किए और ऊपर की पोस्ट अपडेट की।
डेविड वुड

2

मैं एक और संभावना के लिए जोड़ना चाहता हूं। यदि आप TypeToken का उपयोग नहीं करना चाहते हैं और एक ऑब्जेक्ट को सरणी ऑब्जेक्ट्स को ArrayList में बदलना चाहते हैं, तो आप इस तरह से आगे बढ़ सकते हैं:

यदि आपकी json संरचना इस प्रकार है:

{

"results": [
    {
        "a": 100,
        "b": "value1",
        "c": true
    },
    {
        "a": 200,
        "b": "value2",
        "c": false
    },
    {
        "a": 300,
        "b": "value3",
        "c": true
    }
]

}

और आपकी कक्षा संरचना इस प्रकार है:

public class ClassName implements Parcelable {

    public ArrayList<InnerClassName> results = new ArrayList<InnerClassName>();
    public static class InnerClassName {
        int a;
        String b;
        boolean c;      
    }
}

तो आप इसे पसंद कर सकते हैं:

Gson gson = new Gson();
final ClassName className = gson.fromJson(data, ClassName.class);
int currentTotal = className.results.size();

अब आप className ऑब्जेक्ट के प्रत्येक तत्व तक पहुँच सकते हैं।


1

Gson के 'प्रकार' वर्ग की समझ के लिए उदाहरण 2 का संदर्भ लें।

उदाहरण 1: इस deserilizeResturant में हमने Employee [] सरणी का उपयोग किया और विवरण प्राप्त किया

public static void deserializeResturant(){

       String empList ="[{\"name\":\"Ram\",\"empId\":1},{\"name\":\"Surya\",\"empId\":2},{\"name\":\"Prasants\",\"empId\":3}]";
       Gson gson = new Gson();
       Employee[] emp = gson.fromJson(empList, Employee[].class);
       int numberOfElementInJson = emp.length();
       System.out.println("Total JSON Elements" + numberOfElementInJson);
       for(Employee e: emp){
           System.out.println(e.getName());
           System.out.println(e.getEmpId());
       }
   }

उदाहरण 2:

//Above deserilizeResturant used Employee[] array but what if we need to use List<Employee>
public static void deserializeResturantUsingList(){

    String empList ="[{\"name\":\"Ram\",\"empId\":1},{\"name\":\"Surya\",\"empId\":2},{\"name\":\"Prasants\",\"empId\":3}]";
    Gson gson = new Gson();

    // Additionally we need to se the Type then only it accepts List<Employee> which we sent here empTypeList
    Type empTypeList = new TypeToken<ArrayList<Employee>>(){}.getType();


    List<Employee> emp = gson.fromJson(empList, empTypeList);
    int numberOfElementInJson = emp.size();
    System.out.println("Total JSON Elements" + numberOfElementInJson);
    for(Employee e: emp){
        System.out.println(e.getName());
        System.out.println(e.getEmpId());
    }
}

0

मुझे kays1 से जवाब पसंद आया लेकिन मैं इसे लागू नहीं कर सका। इसलिए मैंने उनकी अवधारणा का उपयोग करके अपना संस्करण बनाया।

public class JsonListHelper{
    public static final <T> List<T> getList(String json) throws Exception {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        Type typeOfList = new TypeToken<List<T>>(){}.getType();
        return gson.fromJson(json, typeOfList);
    }
}

उपयोग:

List<MyClass> MyList= JsonListHelper.getList(jsonArrayString);

जब से आप संकलन-समय में T का उपयोग करने का प्रयास कर रहे हैं, निश्चित रूप से यह काम नहीं कर सकता है। यह प्रभावी रूप से स्ट्रिंगपाइप की सूची की तुलना में प्रभावी होगा, नहीं?
JHH

0

मेरे मामले में @ uncaught_exception के जवाब से काम नहीं चला, मुझे List.classइसके बजाय उपयोग करना पड़ा java.lang.reflect.Type:

String jsonDuplicatedItems = request.getSession().getAttribute("jsonDuplicatedItems").toString();
List<Map.Entry<Product, Integer>> entries = gson.fromJson(jsonDuplicatedItems, List.class);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.