2015-10-26 6 views
10

के साथ उपclass के लिए कस्टम कनवर्टर मेरे पास एक उपयोगकर्ता वर्ग है। और दो उप-वर्ग। अभिभावक और बच्चे। मुझे अपने सर्वर से जेसन मिल गया है {"उपयोगकर्ता": "..."} और इसे उपयोगकर्ता के आधार पर माता-पिता या बच्चे के रूप में परिवर्तित करने की आवश्यकता है। टाइपमोशी

जैसा कि मैं समझता हूं कि मुझे कस्टम कनवर्टर को इस तरह जोड़ने की आवश्यकता है:

 Moshi moshi = new Moshi.Builder() 
      .add(new UserAdapter()) 
      .build(); 

यहां उपयोगकर्ता एडाप्टर का मेरा कार्यान्वयन है। मैं जानता हूँ कि यह डमी है, लेकिन यह भी इस तरह से काम नहीं कर रहा:

सभी की
public class UserAdapter { 

@FromJson 
User fromJson(String userJson) { 
    Moshi moshi = new Moshi.Builder().build(); 
    try { 
     JSONObject jsonObject = new JSONObject(userJson); 
     String accountType = jsonObject.getString("type"); 

     switch (accountType) { 
      case "Child": 
       JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class); 
       return childJsonAdapter.fromJson(userJson); 
      case "Parent": 
       JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class); 
       return parentJsonAdapter.fromJson(userJson); 

     } 
    } catch (JSONException | IOException e) { 
     e.printStackTrace(); 
    } 

    return null; 
} 

@ToJson 
String toJson(User user) { 
    Moshi moshi = new Moshi.Builder().build(); 
    JsonAdapter<User> jsonAdapter = moshi.adapter(User.class); 
    String toJson = jsonAdapter.toJson(user); 
    return toJson; 
} 

सबसे पहले मैं इस कोड के साथ अपवाद निम्न मिलता है।

com.squareup.moshi.JsonDataException: Expected a string but was BEGIN_OBJECT at path $.user 

और दूसरा, मेरा मानना ​​है कि ऐसा करने का एक बेहतर तरीका है। कृपया सलाह दें।

अद्यतन। यहाँ त्रुटि के लिए स्टैकट्रेस है:

com.squareup.moshi.JsonDataException: Expected a name but was BEGIN_OBJECT at path $.user 
at com.squareup.moshi.JsonReader.nextName(JsonReader.java:782) 
at com.squareup.moshi.ClassJsonAdapter.fromJson(ClassJsonAdapter.java:141) 
at com.squareup.moshi.JsonAdapter$1.fromJson(JsonAdapter.java:68) 
at com.squareup.moshi.JsonAdapter.fromJson(JsonAdapter.java:33) 
at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:33) 
at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:23) 
at retrofit.OkHttpCall.parseResponse(OkHttpCall.java:148) 
at retrofit.OkHttpCall.execute(OkHttpCall.java:116) 
at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:111) 
at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:88) 
at rx.Observable$2.call(Observable.java:162) 
at rx.Observable$2.call(Observable.java:154) 
at rx.Observable$2.call(Observable.java:162) 
at rx.Observable$2.call(Observable.java:154) 
at rx.Observable.unsafeSubscribe(Observable.java:7710) 
at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62) 
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) 
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
at java.lang.Thread.run(Thread.java:818) 

उत्तर

6

यह उदाहरण आप अपने कस्टम डी/अपने JSON डेटा की क्रमबद्धता के लिए पालन करना चाहते हैं की तरह मुझे लगता है: https://github.com/square/moshi#another-example

यह एक मध्यवर्ती वर्ग कि JSON से मेल खाती है का उपयोग करता है संरचना, और मोशी इसे आपके लिए स्वचालित रूप से फुलाएगी। फिर, आप अपने विशेष उपयोगकर्ता कक्षाओं को बनाने के लिए फुले हुए डेटा का उपयोग कर सकते हैं।

// Intermediate class with JSON structure 
class UserJson { 
    // Common JSON fields 
    public String type; 
    public String name; 
    // Parent JSON fields 
    public String occupation; 
    public Long salary; 
    // Child JSON fields 
    public String favorite_toy; 
    public Integer grade; 
} 

abstract class User { 
    public String type; 
    public String name; 
} 

final class Parent extends User { 
    public String occupation; 
    public Long salary; 
} 

final class Child extends User { 
    public String favoriteToy; 
    public Integer grade; 
} 

अब, अनुकूलक: उदाहरण के लिए:

class UserAdapter { 
    // Note that you pass in a `UserJson` object here 
    @FromJson User fromJson(UserJson userJson) { 
    switch (userJson.type) { 
    case "Parent": 
     final Parent parent = new Parent(); 
     parent.type = userJson.type; 
     parent.name = userJson.name; 
     parent.occupation = userJson.occupation; 
     parent.salary = userJson.salary; 
     return parent; 
    case "Child": 
     final Child child = new Child(); 
     child.type = userJson.type; 
     child.name = userJson.name; 
     child.favoriteToy = userJson.favorite_toy; 
     child.grade = userJson.grade; 
     return child; 
    default: 
     return null; 
    } 
    } 

    // Note that you return a `UserJson` object here. 
    @ToJson UserJson toJson(User user) { 
    final UserJson json = new UserJson(); 
    if (user instanceof Parent) { 
     json.type = "Parent"; 
     json.occupation = ((Parent) user).occupation; 
     json.salary = ((Parent) user).salary; 
    } else { 
     json.type = "Child"; 
     json.favorite_toy = ((Child) user).favoriteToy; 
     json.grade = ((Child) user).grade; 
    } 
    json.name = user.name; 
    return json; 
    } 
} 

मुझे लगता है कि यह अधिक स्वच्छ है, और मोशी अपनी बात है, जो JSON से वस्तुओं का निर्माण करने और वस्तुओं से JSON पैदा कर रही है करने के लिए अनुमति देता है। पुरानी शैली JSONObject के साथ चारों ओर कोई चकित नहीं!

परीक्षण करने के लिए:

Child child = new Child(); 
child.type = "Child"; 
child.name = "Foo"; 
child.favoriteToy = "java"; 
child.grade = 2; 
Moshi moshi = new Moshi.Builder().add(new UserAdapter()).build(); 
try { 
    // Serialize 
    JsonAdapter<User> adapter = moshi.adapter(User.class); 
    String json = adapter.toJson(child); 
    System.out.println(json); 
    // Output is: {"favorite_toy":"java","grade":2,"name":"Foo","type":"Child"} 

    // Deserialize 
    // Note the cast to `Child`, since this adapter returns `User` otherwise. 
    Child child2 = (Child) adapter.fromJson(json); 
    System.out.println(child2.name); 
    // Output is: Foo 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
+0

अरे, आप answear के लिए धन्यवाद, मैं इस सप्ताह अपने कोड की जाँच करें और निशान के रूप में corect अगर यह काम करता है – Defuera

+0

@Defuera Ну как करने की कोशिश करेंगे? कोइ भाग्य? – savanto

+0

@Savanto एक एडाप्टर आवश्यक है? –

3

आप शायद करने की कोशिश की आप के अनुसार पार्स करने को लागू करने: https://github.com/square/moshi#custom-type-adapters

वहाँ स्ट्रिंग @FromJson विधि का एक तर्क के रूप में प्रयोग किया जाता है, तो यह जादुई कुछ मानचित्रण के लिए पार्स किया जा सकता सहायक वर्ग या स्ट्रिंग और हमें इसे मैन्युअल रूप से पार्स करना है, है ना? दरअसल, आप या तो मैपिंग सहायक वर्ग या मानचित्र का उपयोग कर सकते हैं।

इस प्रकार आपका अपवाद Expected a string but was BEGIN_OBJECT at path $.user मोशी द्वारा उस उपयोगकर्ता को स्ट्रिंग के रूप में प्राप्त करने की कोशिश कर रहा था (क्योंकि यही वह है जिसे आपने अपने एडाप्टर में बताया है), जबकि यह एक और वस्तु है।

मुझे कुछ सहायक क्षेत्रों में सभी संभावित फ़ील्ड को पार्स करना पसंद नहीं है क्योंकि बहुरूपता के मामले में कक्षा बहुत बड़ी हो सकती है और आपको कोड पर भरोसा या याद रखना/टिप्पणी करना होगा।

आप एक नक्शे के रूप में यह संभाल कर सकते हैं - कि अज्ञात प्रकार का डिफ़ॉल्ट मॉडल है - और यह json में बदलने का है, तो आपके मामले में ऐसा ही कुछ दिखेगा:

@FromJson 
    User fromJson(Map<String, String> map) { 
     Moshi moshi = new Moshi.Builder().build(); 
     String userJson = moshi.adapter(Map.class).toJson(map); 
     try { 
      JSONObject jsonObject = new JSONObject(userJson); 
      String accountType = jsonObject.getString("type"); 

      switch (accountType) { 
       case "Child": 
        JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class); 
        return childJsonAdapter.fromJson(userJson); 
       case "Parent": 
        JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class); 
        return parentJsonAdapter.fromJson(userJson); 

      } 
     } catch (JSONException | IOException e) { 
      e.printStackTrace(); 
     } 

     return null; 
    } 

बेशक आप सिर्फ नक्शा संभाल कर सकते हैं का सीधे: "प्रकार" स्ट्रिंग पुनर्प्राप्त करें और फिर शेष वर्ग को शेष वर्ग पर पार्स करें।इसके बाद एंड्रॉइड पर निर्भर नहीं होने और पार्सिंग के आसान परीक्षण के अच्छे लाभ के साथ JSONObject का उपयोग करने की आवश्यकता नहीं है।

@FromJson 
    User fromJson(Map<String, String> map) { 
     Moshi moshi = new Moshi.Builder().build(); 
     try { 
      String userJson = moshi.adapter(Map.class).toJson(map); 
      switch (map.get("type")) { 
       case "Child": 
        JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class); 
        return childJsonAdapter.fromJson(userJson); 
       case "Parent": 
        JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class); 
        return parentJsonAdapter.fromJson(userJson); 

      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     return null; 
    }