2016-06-28 12 views
5

के लिए इंटरफ़ेस deserialize मैं रेट्रोफिट 2.1.0 उपयोग कर रहा हूँ कनवर्टर-gson साथ: 2.1.0 और अलग से gson: 2.6.2 क्रमबद्धता/अक्रमांकन कस्टमाइज़ करने के लिए। समस्या यह है कि मेरे पीओजेओ को इंटरफेस के पीछे छुपाया जाना चाहिए और मैं जीएसएस को बताना चाहता हूं कि कौन सा वर्ग deserialized इंटरफ़ेस होना चाहिए। और deserialization/serialization retrofit इंटरफ़ेस वापस करने में सक्षम होना चाहिए के बाद। यह अच्छा होगा अगर मैं जेनरिक का लाभ उठा सकता हूं और FooClace को FooInterface को क्रमबद्ध/deserialize करने के लिए आसानी से Gson या Retrofit को बताने का एक तरीका बना सकता हूं।Gson अपनी कक्षा कार्यान्वयन

उत्तर

11

मुझे लगता है कि आप अपने सभी इंटरफेस और उनके संबंधित कार्यान्वयन के लिए एक एकल deserializer बनाना चाहते हैं। इन चरणों का पालन करें कृपया:

1. एक बेस इंटरफ़ेस बनाएं जो आपके अन्य ऐप इंटरफेस द्वारा बढ़ाया जाएगा। अपने सभी इंटरफेस और कार्यान्वयन कक्षाओं के लिए एक एकल deserializer बनाने की आवश्यकता है।

public interface Convertable { 
    String getClassName(); 
} 

2. अपनी सुविधा इंटरफेस और कार्यान्वयन वर्ग बनाएँ। उदाहरण के तौर पर, उन्हें FooInterface और FooClass नाम दें। FooInterface कन्वर्ट करने योग्य इंटरफ़ेस का विस्तार करना चाहिए।

FooInterface

public interface FooInterface extends Convertable { 

} 

FooClass

public class FooClass implements FooInterface { 

    // DISCRIMINATOR FIELD 
    private final String className; 

    private String field1; 

    private String field2; 

    public FooClass() { 
     this.className = getClass().getName(); 
    } 

    public String getClassName() { 
     return className; 
    } 

    public String getField1() { 
     return field1; 
    } 

    public void setField1(String field1) { 
     this.field1 = field1; 
    } 

    public String getField2() { 
     return field2; 
    } 

    public void setField2(String field2) { 
     this.field2 = field2; 
    } 

} 

ध्यान दें कि getClassName() द्वारा दिए गए मान discriminator क्षेत्र है कि करने के लिए Gson deserializer (अगले कदम) में इस्तेमाल किया जाएगा के रूप में प्रयोग किया जाता है वापसी योग्य उदाहरण शुरू करें। मुझे लगता है कि आपका सीरियलाइज़र और deserializer क्लास एक ही पैकेज में रहेंगे भले ही वे अलग-अलग क्लाइंट और सर्वर अनुप्रयोगों में हों। यदि नहीं, तो आपको getClassInstance() कार्यान्वयन को बदलने की आवश्यकता होगी, लेकिन ऐसा करने के लिए बहुत आसान होगा।

3. आपके आवेदन

import com.google.gson.JsonDeserializationContext; 
import com.google.gson.JsonDeserializer; 
import com.google.gson.JsonElement; 
import com.google.gson.JsonObject; 
import com.google.gson.JsonParseException; 
import com.google.gson.JsonPrimitive; 

public class ConvertableDeserializer<T extends Convertable> implements JsonDeserializer<T> { 

    private static final String CLASSNAME = "className"; 

    public T deserialize(final JsonElement jsonElement, final Type type, 
         final JsonDeserializationContext deserializationContext 
         ) throws JsonParseException { 

     final JsonObject jsonObject = jsonElement.getAsJsonObject(); 
     final JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME); 
     final String className = prim.getAsString(); 
     final Class<T> clazz = getClassInstance(className); 
     return deserializationContext.deserialize(jsonObject, clazz); 
    } 

    @SuppressWarnings("unchecked") 
    public Class<T> getClassInstance(String className) { 
     try { 
      return (Class<T>) Class.forName(className); 
     } catch (ClassNotFoundException cnfe) { 
      throw new JsonParseException(cnfe.getMessage()); 
     } 
    } 

} 

4. रजिस्टर Gson साथ deserializer के सभी के लिए एक कस्टम Gson Serializer कार्यान्वित करके प्रारंभ पुराना वापस

private static GsonConverterFactory buildGsonConverter() { 

     final GsonBuilder builder = new GsonBuilder(); 

     // Adding custom deserializers 
     builder.registerTypeAdapter(FooInterface.class, 
            new ConvertableDeserializer<FooInterface>()); 
     final Gson gson = builder.create(); 

     return GsonConverterFactory.create(myGson); 
    } 


    public void initRetrofit() { 
     Retrofit retrofit = new Retrofit.Builder() 
       .baseUrl("REST_ENDPOINT") 
       .addConverterFactory(buildGsonConverter()) 
       .client(httpClient) 
       .build(); 
    } 

आप सभी के लिए एडाप्टर पंजीकृत कर सकते हैं यदि आप चाहते हैं तो अपने कार्यान्वयन का उपयोग करके:

builder.registerTypeAdapter(Convertable.class, new ConvertableDeserializer<Convertable>()); 
+0

मैं इस कार्यान्वयन और रिपोर्ट की जाँच करेगा। – toshkinl

+0

क्या आपने इसे जांचने में कामयाब रहे? –

+0

मैं 'एनपीई 'लाइन' अंतिम स्ट्रिंग क्लासनाम = prim.getAsString();' कन्वर्टेबल डीसेरियलाइज़र 'वर्ग पर पुनर्प्राप्त करता हूं। और यह स्पष्ट है। मेरे जेसन में इसके अंदर 'className' फ़ील्ड नहीं है। – IlyaEremin

3

क्योंकि आप लगभग अपने मॉडल के कार्यान्वयन के विस्तार को छिपाने के लिए, मुझे लगता है कि आप मेरा उत्तर refresing मिलेगा इंटरफेस का उपयोग कर अपने संपूर्ण डोमेन परत नकल करने के प्रयास लेने के लिए तैयार कर रहे हैं;)

आप AutoValue क्रम में उपयोग करना चाहिए अपने मॉडल में किसी भी कार्यान्वयन विस्तार को छिपाने के लिए। जिस तरह से यह काम करता है वह बहुत आसान है:

आप एक अमूर्त वर्ग लिखते हैं, और ऑटोवैल्यू इसे लागू करता है। यह सब है; सचमुच कोई विन्यास नहीं है।

इस दृष्टिकोण को अपनाने के लिए आपको ऐसी बॉयलरप्लेट बनाने की आवश्यकता नहीं होगी।

और इस ऑटोवैल्यू एक्सटेंशन को auto-value-gson कहा जाता है, जो बॉक्स के बाहर गसन डी/सीरिएलाइज़र समर्थन को जोड़ता है।

इन आसान चरणों के साथ मुझे लगता है कि अपने कोड बेस काफी हद तक सुधार होगा।

+0

क्या आप एक उदाहरण प्रदान कर सकते हैं? –