2014-10-09 94 views
6

我有一些JSON進來(我沒有任何控制或能力來改變結構和/或命名內JSON ...重要的是要記住在這個問題),有一個「扁平」結構類似於這樣的:gson flat json嵌套對象需要串行器/解串器嗎?

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


現在,我就可以創建一個簡單的對象,使一切平,像這樣:

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; 

    ... 
} 


但是,我希望與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 2017-03-02 07:30:05

+0

@Umair不,還沒有。還在等待。抱歉。 – bsara 2017-03-02 19:47:42

回答

0

的TypeAdapter是不是唯一的方法,但在這種情況下,會因爲你可以關聯起來的最佳方式帶有Gson實例的適配器(或者您正在使用的任何庫),並且具有您所有的映射代碼。

另一種方法是使用JAVA反射。我之前在項目中使用了以下代碼版本,但從未使用過JSON,也從來沒有嵌套對象(大多數時候沒有其他選擇,或者如果我想將SQL結果集映射到Java對象,而無需調用resultSet.get...次)。

這將在這種情況下工作。

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]]