2013-05-06 9 views
18

के साथ जीसन का उपयोग करना मैं कुछ सर्वर कोड पर काम कर रहा हूं, जहां क्लाइंट JSON के रूप में अनुरोध भेजता है। मेरी समस्या यह है कि, कई संभावित अनुरोध हैं, सभी छोटे कार्यान्वयन विवरणों में भिन्न हैं। इसलिए मैं एक अनुरोध इंटरफ़ेस का उपयोग करने के लिए सोचा, के रूप में परिभाषित:इंटरफ़ेस प्रकार

public interface Request { 
    Response process (); 
} 

वहाँ से, मैं LoginRequest नाम के एक वर्ग में इंटरफ़ेस प्रदर्शित के रूप में लागू:

public class LoginRequest implements Request { 
    private String type = "LOGIN"; 
    private String username; 
    private String password; 

    public LoginRequest(String username, String password) { 
     this.username = username; 
     this.password = password; 
    } 

    public String getType() { 
     return type; 
    } 
    public void setType(String type) { 
     this.type = type; 
    } 
    public String getUsername() { 
     return username; 
    } 
    public void setUsername(String username) { 
     this.username = username; 
    } 
    public String getPassword() { 
     return password; 
    } 
    public void setPassword(String password) { 
     this.password = password; 
    } 

    /** 
    * This method is what actually runs the login process, returning an 
    * appropriate response depending on the outcome of the process. 
    */ 
    @Override 
    public Response process() { 
     // TODO: Authenticate the user - Does username/password combo exist 
     // TODO: If the user details are ok, create the Player and add to list of available players 
     // TODO: Return a response indicating success or failure of the authentication 
     return null; 
    } 

    @Override 
    public String toString() { 
     return "LoginRequest [type=" + type + ", username=" + username 
      + ", password=" + password + "]"; 
    } 
} 

JSON के साथ काम करने के लिए, मेरे द्वारा बनाए गए एक GsonBuilder उदाहरण और एक InstanceCreator पंजीकृत दिखाया गया है:

public class LoginRequestCreator implements InstanceCreator<LoginRequest> { 
    @Override 
    public LoginRequest createInstance(Type arg0) { 
     return new LoginRequest("username", "password"); 
    } 
} 

जो मैं तो के रूप में इस्तेमाल किया में दिखाया गया है नीचे स्निपेट:

GsonBuilder builder = new GsonBuilder(); 
builder.registerTypeAdapter(LoginRequest.class, new LoginRequestCreator()); 
Gson parser = builder.create(); 
Request request = parser.fromJson(completeInput, LoginRequest.class); 
System.out.println(request); 

और मुझे अपेक्षित आउटपुट मिलता है।

मैं जिस चीज को करना चाहता हूं वह Request request = parser.fromJson(completeInput, LoginRequest.class); को Request request = parser.fromJson(completeInput, Request.class); जैसा कुछ है, लेकिन ऐसा करने से यह काम नहीं करेगा, क्योंकि Request एक इंटरफ़ेस है।

मैं प्राप्त 0 JSप्राप्त JSON के आधार पर उचित प्रकार के अनुरोध को वापस करने के लिए चाहता हूं।

JSON मैं सर्वर से पारित कर दिया का एक उदाहरण नीचे दिखाया गया है:

{ 
    "type":"LOGIN", 
    "username":"someuser", 
    "password":"somepass" 
} 

दोहराना के लिए, मैं एक तरह से ग्राहकों से अनुरोध (JSON में) पार्स करने और लागू करने वर्गों की वस्तुओं लौटने के लिए देख रहा हूँ Request इंटरफ़ेस

+0

क्या आप सर्वर से प्राप्त विभिन्न JSON प्रतिक्रियाओं के अन्य उदाहरण प्रदान कर सकते हैं? क्योंकि यदि आपके पास कई और बहुत अलग संभावनाएं नहीं हैं, तो कुछ ऐसा आसान है जो आप आसानी से कर सकते हैं ... – MikO

+0

धन्यवाद आपके इनपुट के लिए @MiKO। अन्य संभावित अनुरोध 'PlayRequest',' LogoutRequest', 'GetPlayersRequest', 'JoinGameRequest',' StartGameRequest' आदि ... – fredmanglis

+0

मेरा मतलब है कि यदि आप उन अन्य प्रकार के अनुरोधों में से कम से कम एक के लिए JSON अनुरोध का उदाहरण प्रदान कर सकते हैं । मेरा मतलब है, आपके 'loginRequest' के लिए आपके पास फ़ाइल्स हैं:' टाइप', 'उपयोगकर्ता नाम' और 'पासवर्ड', अन्य अनुरोधों के बारे में क्या? वो कैसे दिखते हैं? – MikO

उत्तर

7

यह मानते हुए कि विभिन्न संभव JSON अनुरोध आप हो सकता है एक दूसरे से बेहद अलग नहीं हैं, मैं एक अलग दृष्टिकोण, मेरी राय में सरल सुझाव देते हैं।

{ 
    "type":"LOGIN", 
    "username":"someuser", 
    "password":"somepass" 
} 
//////////////////////////////// 
{ 
    "type":"SOMEREQUEST", 
    "param1":"someValue", 
    "param2":"someValue" 
} 
//////////////////////////////// 
{ 
    "type":"OTHERREQUEST", 
    "param3":"someValue" 
} 

Gson, आप सब संभव प्रतिक्रियाओं रैप के लिए एक एकल वर्ग की अनुमति देता है इस तरह::

public class Request { 
    @SerializedName("type") 
    private String type; 
    @SerializedName("username") 
    private String username; 
    @SerializedName("password") 
    private String password; 
    @SerializedName("param1") 
    private String param1; 
    @SerializedName("param2") 
    private String param2; 
    @SerializedName("param3") 
    private String param3; 
    //getters & setters 
} 

तक

मान लीजिए कि आप इन 3 अलग JSON अनुरोध है कि चलो एनोटेशन @SerializedName का उपयोग करते हुए, जब जीसन JSON अनुरोध को पार्स करने का प्रयास करता है, तो यह उसी नाम के साथ JSON अनुरोध में कोई फ़ील्ड है, तो कक्षा में प्रत्येक नामांकित विशेषता के लिए, बस देखो। यदि ऐसा कोई क्षेत्र नहीं है, तो कक्षा में विशेषता null पर सेट की गई है।

इस तरह से आप इस तरह, केवल अपने Request वर्ग का उपयोग कर कई अलग अलग JSON प्रतिक्रियाओं पार्स कर सकते हैं:

Gson gson = new Gson(); 
Request request = gson.fromJson(jsonString, Request.class); 

बार जब आप अपने JSON अनुरोध अपनी कक्षा में पार्स है, तो आप रैप से डेटा ट्रांसफर कर सकते हैं एक ठोस XxxxRequest वस्तु को वर्ग, की तरह कुछ:

switch (request.getType()) { 
    case "LOGIN": 
    LoginRequest req = new LoginRequest(request.getUsername(), request.getPassword()); 
    break; 
    case "SOMEREQUEST": 
    SomeRequest req = new SomeRequest(request.getParam1(), request.getParam2()); 
    break; 
    case "OTHERREQUEST": 
    OtherRequest req = new OtherRequest(request.getParam3()); 
    break; 
} 

ध्यान दें कि इस दृष्टिकोण में थोड़ा और अधिक कठिन हो जाता है, तो आप कई अलग अलग JSON अनुरोध और उन requ है ests एक दूसरे के लिए बहुत अलग हैं, लेकिन मुझे लगता है कि एक अच्छा और बहुत ही सरल दृष्टिकोण है ...

+0

धन्यवाद @MikO। मुझे लगता है कि 'स्विच-केस' संरचना कुछ प्रकार के अनुरोध कारखाने में जा सकती है। धन्यवाद। वह सहायक था। मुझे उसमें देखने दो। – fredmanglis

+0

हां, स्विच को 'RequestFactory' वर्ग में डालने से निश्चित रूप से समझ में आता है। – MikO

0

डिफ़ॉल्ट रूप से, जीएसओएन जेएसओएन के रूप में क्रमबद्ध वर्गों को अलग नहीं कर सकता; दूसरे शब्दों में, आपको स्पष्ट रूप से पार्सर को यह बताने की आवश्यकता होगी कि आप किस वर्ग की अपेक्षा कर रहे हैं।

एक समाधान हो सकता है के रूप में वर्णित hereकस्टम deserializing या एक प्रकार एडाप्टर का उपयोग कर,।

23

वर्णित प्रकार के पॉलीमोर्फिक मैपिंग जीसन में कुछ कस्टम कोडिंग के बिना उपलब्ध नहीं है। एक एक्सटेंशन प्रकार एडाप्टर उपलब्ध है as an extra जो कि आप जिस कार्यक्षमता की तलाश कर रहे हैं उसका एक बड़ा हिस्सा प्रदान करता है, जिसमें गुफा के साथ पॉलिमॉर्फिक उप-प्रकारों को एडाप्टर को समय से पहले घोषित करने की आवश्यकता होती है। यहाँ इसके उपयोग का एक उदाहरण है:

public interface Response {} 

public interface Request { 
    public Response process(); 
} 

public class LoginRequest implements Request { 
    private String userName; 
    private String password; 

    // Constructors, getters/setters, overrides 
} 

public class PingRequest implements Request { 
    private String host; 
    private Integer attempts; 

    // Constructors, getters/setters, overrides 
} 

public class RequestTest { 

    @Test 
    public void testPolymorphicSerializeDeserializeWithGSON() throws Exception { 
     final TypeToken<List<Request>> requestListTypeToken = new TypeToken<List<Request>>() { 
     }; 

     final RuntimeTypeAdapterFactory<Request> typeFactory = RuntimeTypeAdapterFactory 
       .of(Request.class, "type") 
       .registerSubtype(LoginRequest.class) 
       .registerSubtype(PingRequest.class); 

     final Gson gson = new GsonBuilder().registerTypeAdapterFactory(
       typeFactory).create(); 

     final List<Request> requestList = Arrays.asList(new LoginRequest(
       "bob.villa", "passw0rd"), new LoginRequest("nantucket.jones", 
       "crabdip"), new PingRequest("example.com", 5)); 

     final String serialized = gson.toJson(requestList, 
       requestListTypeToken.getType()); 
     System.out.println("Original List: " + requestList); 
     System.out.println("Serialized JSON: " + serialized); 

     final List<Request> deserializedRequestList = gson.fromJson(serialized, 
       requestListTypeToken.getType()); 

     System.out.println("Deserialized list: " + deserializedRequestList); 
    } 
} 

ध्यान दें कि आप वास्तव में व्यक्ति जावा वस्तुओं पर type संपत्ति को परिभाषित करने की जरूरत नहीं है - यह केवल JSON में मौजूद है।

+3

उन लोगों के लिए जो 'RuntimeTypeAdapterFactory' गायब हैं, आप इस [gson-extras] (https://github.com/DanySK/gson-extras) का उपयोग कर सकते हैं जो मैवेन-सेंट्रल पर उपलब्ध है (प्रोजेक्ट का उद्देश्य केवल इसे बनाना है मेवेन-सेंट्रल पर उपलब्ध)। – Tomask

4

Genson लाइब्रेरी डिफ़ॉल्ट रूप से पॉलिमॉर्फिक प्रकारों के लिए समर्थन प्रदान करता है। यहां बताया गया है कि यह कैसे काम करेगा:

// tell genson to enable polymorphic types support 
Genson genson = new Genson.Builder().setWithClassMetadata(true).create(); 

// json value will be {"@class":"mypackage.LoginRequest", ... other properties ...} 
String json = genson.serialize(someRequest); 
// the value of @class property will be used to detect that the concrete type is LoginRequest 
Request request = genson.deserialize(json, Request.class); 

आप अपने प्रकार के लिए उपनाम का भी उपयोग कर सकते हैं।

// a better way to achieve the same thing would be to use an alias 
// no need to use setWithClassMetadata(true) as when you add an alias Genson 
// will automatically enable the class metadata mechanism 
genson = new Genson.Builder().addAlias("loginRequest", LoginRequest.class).create(); 

// output is {"@class":"loginRequest", ... other properties ...} 
genson.serialize(someRequest); 
संबंधित मुद्दे