2014-10-09 5 views
6

मेरे पास कुछ JSON आ रहा है (मेरे पास JSON के भीतर संरचना और/या नामकरण को बदलने का कोई नियंत्रण या क्षमता नहीं है ... इस प्रश्न में ध्यान में रखना महत्वपूर्ण है) जिसमें "फ्लैट" संरचना समान है इस:जीसन फ्लैट जेसन ने नेस्टेड ऑब्जेक्ट्स को सीरियलाइज़र/डेसेरियलाइज़र की आवश्यकता है?

public class Settings { 

    @SerializedName("name") 
    private String _name; 

    @SerializedName("email") 
    private String _emailAddress; 

    @SerializedName("box_background_color") 
    private String _boxBackgroundColor; 

    @SerializedName("box_border_color") 
    private String _boxBorderColor; 

    @SerializedName("box_text_color") 
    private String _boxTextColor; 

    ... 
} 


:

{ 
    "name": "...", 
    "email": "...", 
    "box_background_color": "...", 
    "box_border_color": "...", 
    "box_text_color": "...", 
    ... 
} 


अब, मैं सिर्फ एक सरल उद्देश्य यह है कि सब कुछ फ्लैट, इसलिए की तरह रहता है बना सकते हैं

हालांकि, मैं box सेटिंग्स से जुड़ी सब कुछ अपनी कक्षा में होना चाहता हूं (BoxSettings)। यह और अधिक की तरह मैं क्या चाहते है:

public class Settings { 

    @SerializedName("name") 
    private String _name; 

    @SerializedName("email") 
    private String _emailAddress; 

    private BoxSettings _boxSettings 

    ... 
} 

public class BoxSettings { 

    @SerializedName("box_background_color") 
    private String _boxBackgroundColor; 

    @SerializedName("box_border_color") 
    private String _boxBorderColor; 

    @SerializedName("box_text_color") 
    private String _boxTextColor; 

    ... 
} 


मुझे पता है कि अगर इस तरह के JSON संरचित किया गया था कि बॉक्स सेटिंग्स तो नेस्ट गया यह पूरा करने के लिए जो मैं चाहता आसान होगा, फिर भी, मैं डॉन JSON की संरचना को बदलने की क्षमता नहीं है, इसलिए कृपया यह सुझाव न दें कि (अगर मैं कर सकता तो मैं करूँगा)। एक पूरे TypeAdapter एक ही रास्ता पूरा करने के लिए मैं क्या चाहते हैं या मैं अभी भी एनोटेशन के साथ इस का सबसे पूरा कर सकते हैं बनाने है:

मेरा प्रश्न है? यदि यह एकमात्र तरीका नहीं है, तो मैं JSON को बदले बिना इसे और कैसे पूरा कर सकता हूं?

निम्नलिखित मैं क्या द्वारा "एक पूरी TypeAdapter बनाने" मतलब का एक उदाहरण है:

public class SettingsTypeAdapter implements JsonDeserializer<Settings>, JsonSerializer<Settings> { 

    @Override 
    public JsonElement serialize(Settings src, Type typeOfSrc, JsonSerializationContext context) { 
    // Add _name 
    // Add _emailAddress 
    // Add BoxSettings._boxBackgroundColor 
    // Add BoxSettings._boxBorderColor 
    // Add BoxSettings._boxTextColor 
    return jsonElement; 
    } 

    @Override 
    public Settings deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
    // Read _name 
    // Read _emailAddress 
    // Read BoxSettings._boxBackgroundColor 
    // Read BoxSettings._boxBorderColor 
    // Read BoxSettings._boxTextColor 
    return settings; 
    } 
} 
+0

आप किसी भी समाधान मिला? – Umair

+0

@Umair नहीं, अभी तक नहीं। अब भी इंतज़ार। माफ़ कीजिये। – bsara

उत्तर

0

TypeAdapter एकमात्र तरीका नहीं है, लेकिन इस मामले में सबसे अच्छा तरीका है जब से तुम संबद्ध कर सकते हैं हो सकता है एक जीसन इंस्टेंस (या जो भी लाइब्रेरी आप उपयोग कर रहे हैं) के साथ एडाप्टर और आपके सभी मैपिंग कोड हैं।

जावावा प्रतिबिंब का उपयोग करने का एक और तरीका है। मैंने पहले अपनी परियोजनाओं में नीचे दिए गए कोड का एक संस्करण इस्तेमाल किया है, लेकिन जेएसओएन के साथ कभी नहीं और कभी भी नेस्टेड ऑब्जेक्ट्स के साथ नहीं (ज्यादातर जब कोई अन्य विकल्प नहीं था या यदि मैं जावा ऑब्जेक्ट को resultSet.get... पर कॉल किए बिना SQL ऑब्जेक्ट को मैप करना चाहता था समय के)।

यह इस मामले में काम करेगा।

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
import java.lang.reflect.Field; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 

import org.json.JSONObject; 

public class Main { 

    public static void main(String[] args) { 

     try { 
      String json = "{\"name\": \"test name\", \"email\": \"[email protected]\", \"box_background_color\": \"red\", \"box_border_color\": \"orange\", \"box_text_color\": \"white\", \"test3_var2\":3}"; 

      JSONObject jsonObject = new JSONObject(json); 

      System.out.println(jsonObject); 
      System.out.println(); 

      /* 
      * need to parse JSON into a map of String, Object 
      */ 

      Map<String, Object> mapAll = new HashMap<String, Object>(); 
      Iterator<String> iter = jsonObject.keys(); 

      while (iter.hasNext()) { 
       String key = (String) iter.next(); 
       Object value = jsonObject.get(key); 

       mapAll.put(key, value); 

       System.out.println(key + "::::" + value); 
      } 

      System.out.println(); 

      /* 
      * use the mapper to generate the objects 
      */ 

      MyMapper<TestClass1> myMapper = new MyMapper<TestClass1>(); 
      TestClass1 result = myMapper.mapToObject(mapAll, TestClass1.class); 

      System.out.println(result); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

    class MyMapper<T> { 

     @SuppressWarnings("unchecked") 
     public T mapToObject(Map<String, Object> flatStructure, Class<T> objectClass) { 
      T result = null; 
      Field[] fields = null; 

      try { 
       // new base object 
       result = objectClass.newInstance(); 

       // get all of its fields 
       fields = objectClass.getDeclaredFields(); 

       for (Field field : fields) { 
        // normal variable 
        if (field.isAnnotationPresent(MyColumn.class)) { 
         String variableKey = field.getAnnotation(MyColumn.class).variableKey(); 

         setJavaFieldValue(result, field.getName(), flatStructure.get(variableKey)); 
        } 
        // variable that is an object and itself has to be mapped 
        else if (field.isAnnotationPresent(MyInnerColumn.class)) { 
         String startsWith = field.getAnnotation(MyInnerColumn.class).startsWith(); 

         // reduce the map to only have attributes that are related to this field 
         Map<String, Object> reducedMap = reduceMap(startsWith, flatStructure); 

         // make sure that there are attributes for the inner object 
         if (reducedMap != null) { 
          // map the inner object 
          MyMapper<T> myMapper = new MyMapper<T>(); 
          T t2 = myMapper.mapToObject(reducedMap, (Class<T>) field.getType()); 

          // set the mapped object to the base objecct 
          setJavaFieldValue(result, field.getName(), t2); 
         } 
        } else { 
         // no annotation on the field so ignored 
        } 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 

      return result; 
     } 

     private Map<String, Object> reduceMap(String startsWith, Map<String, Object> mapToReduce) { 
      Map<String, Object> result = new HashMap<String, Object>(); 

      for (Map.Entry<String, Object> entry : mapToReduce.entrySet()) { 
       if (entry.getKey().toLowerCase().startsWith(startsWith.toLowerCase())) { 
        result.put(entry.getKey(), entry.getValue()); 
       } 
      } 

      return result.size() == 0 ? null : result; 
     } 

     private void setJavaFieldValue(Object object, String fieldName, Object fieldValue) { 
      try { 
       Field field = object.getClass().getDeclaredField(fieldName); 

       boolean fieldAccess = field.isAccessible(); 

       // make the field accessible 
       field.setAccessible(true); 
       field.set(object, fieldValue); 

       // put it back to the way it was 
       field.setAccessible(fieldAccess); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    /* 
    * Annotation for a regular variable/field 
    */ 
    @Target(ElementType.FIELD) 
    @Retention(RetentionPolicy.RUNTIME) 
    @interface MyColumn { 

     // the variable's JSON key 
     String variableKey() default ""; 
    } 

    /* 
    * Annotation for an inner/nested variable/field 
    */ 
    @Target(ElementType.FIELD) 
    @Retention(RetentionPolicy.RUNTIME) 
    @interface MyInnerColumn { 

     /* 
     * JSON keys that start with this string will be 
     * associated with this nested field 
     */ 
     String startsWith() default ""; 
    } 

    class TestClass1 { 
     @MyColumn(variableKey = "name") 
     private String _name; 

     @MyColumn(variableKey = "email") 
     private String _emailAddress; 

     @MyInnerColumn(startsWith = "box_") 
     private TestClass2 innerClass; 

     @MyInnerColumn(startsWith = "test3_") 
     private TestClass3 innerClass2; 

     @Override 
     public String toString() { 
      return "TestClass1 [_name=" + _name + ", _emailAddress=" + _emailAddress + ", innerClass=" + innerClass + ", innerClass2=" + innerClass2 + "]"; 
     } 
    } 

    class TestClass2 { 
     @MyColumn(variableKey = "box_background_color") 
     private String _boxBackgroundColor; 

     @MyColumn(variableKey = "box_border_color") 
     private String _boxBorderColor; 

     @MyColumn(variableKey = "box_text_color") 
     private String _boxTextColor; 

     @Override 
     public String toString() { 
      return "TestClass2 [_boxBackgroundColor=" + _boxBackgroundColor + ", _boxBorderColor=" + _boxBorderColor 
        + ", _boxTextColor=" + _boxTextColor + "]"; 
     } 
    } 

    class TestClass3 { 
     @MyColumn(variableKey = "test3_var1") 
     private String _test3Var1; 

     @MyColumn(variableKey = "test3_var2") 
     private int _test3Var2; 

     @Override 
     public String toString() { 
      return "TestClass3 [_test3Var1=" + _test3Var1 + ", _test3Var2=" + _test3Var2 + "]"; 
     } 
    } 

आउटपुट

{"box_background_color":"red","box_text_color":"white","test3_var2":3,"name":"test name","email":"[email protected]","box_border_color":"orange"} 

box_background_color::::red 
box_text_color::::white 
test3_var2::::3 
name::::test name 
email::::[email protected] 
box_border_color::::orange 

TestClass1 [_name=test name, [email protected], innerClass=TestClass2 [_boxBackgroundColor=red, _boxBorderColor=orange, _boxTextColor=white], innerClass2=TestClass3 [_test3Var1=null, _test3Var2=3]] 
संबंधित मुद्दे