代码之家  ›  专栏  ›  技术社区  ›  Hector

如何用领域将Json映射到有效的Java字段名

  •  0
  • Hector  · 技术社区  · 6 年前

    我当前的Android应用程序使用Realm作为本地数据库。

    我正在用来自第三方API的数据填充我的领域实体。

    这些API生成Json响应消息,我将使用这些消息持久化到realm createAllRealm.createAllFromJson(clazz, json)

    其中一个API具有如下所示的响应消息

    {
      "content": [
        {
          "abstract": "string",
          "article_id": 0,
          "authors": [
            "string"
          ],
          "doi": "string",
          "ending_page": "string",
          "issue": "string",
          "journal_name": "string",
          "publisher": "string",
          "starting_page": "string",
          "title": "string",
          "volume": "string",
          "year": 0
        }
      ],
      "total_number": 0
    }
    

    显然,我的领域数据库对象必须具有完全匹配的字段名,以确保所有响应数据都被持久化,例如:-

        @PrimaryKey
        private Long article_id;
    
        private String authors;
        private Long year;
        private Long ending_page;
        private Long starting_page;
        private String _abstract;
        private String doi;
        private String issue;
        private String journal_name;
        private String publisher;
        private String title;
        private String volume;
    

    由于消息包含一个Json字段名,它是一个Java关键字,例如“abstract”,所以我必须将我的Java字段命名为“abstract”。

    当我持久化这些消息时,抽象总是空的,因为Json和Java字段名不匹配。

    Realm有什么方法可以解决这个问题并且仍然使用createAllFromJson吗?

    或者在持久化响应数据之前,我必须使用Jackson或GSON将Json消息转换为Java对象吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Geo    6 年前

    中提到了一种解决方法 https://github.com/realm/realm-java/issues/1470

    在这个问题解决之前,我已经在我的应用程序中做了一个变通方法,假设我已经 聊天.java

    public class Chat extends RealmObject {
        @Index
        @SerializedName("c")
        private String code = "";
    
        @Index
        @SerializedName("t")
        private int type;
    }
    

    和RealmUtil.java

    public class RealmUtil {
    
    
        private static HashMap<String, HashMap<String, String>> classesFieldsMap = new HashMap<>();
    
        static {
            initClasses(Chat.class);
        }
    
        private static void initClasses(Class cls) {
            if (!classesFieldsMap.containsKey(cls.toString())) {
                Field[] fields = cls.getDeclaredFields();
                HashMap<String, String> fieldsMap = new HashMap<>();
                for (Field a : fields) {
                    SerializedName annotation = a.getAnnotation(SerializedName.class);
                    if (annotation != null) {
                        fieldsMap.put(annotation.value(), a.getName());
                    }
                }
                classesFieldsMap.put(cls.toString(), fieldsMap);
            }
        }
    
        public static JSONObject mapGsonObjectToRealm(Class cls, JSONObject object) throws JSONException {
            JSONObject newUserObj = new JSONObject();
            HashMap<String, String> fieldsMap = classesFieldsMap.get(cls.toString());
            for (String setKey : fieldsMap.keySet()) {
                String mappedKey = fieldsMap.get(setKey);
                if (object.has(setKey))
                    newUserObj.put(mappedKey, object.get(setKey));
            }
            return newUserObj;
        }
    }
    

    通过使用反射initClasses方法,将类的每个Gson SerializedName映射到领域记录的相应名称。

    mapGsonObjectToRealm方法将用新字段名创建旧对象的新对象。

    用法:

    JSONObject newObject = RealmUtil.mapGsonObjectToRealm(Chat.class, new JSONObject().put("c", "this_is_code").put("t", "this_is_type"));
    final JSONArray jsonArray = new JSONArray();
    jsonArray.put(newObject);
    Realm.getDefaultInstance().executeTransactionAsync(new Realm.Transaction() {
        @Override
         public void execute(Realm realm) {
            realm.createOrUpdateAllFromJson(Chat.class, jsonArray);
        }
    });
    
        2
  •  1
  •   Geo    6 年前

    尝试使用@SerializedName注释

    @SerializedName("abstract")  
    private String _abstract;
    

    这个注释在google gson annotations包下,因此可能需要添加gson依赖性