如何使用 Realm 将 Json 映射到有效的 Java 字段名称

How to map Json to valid Java field name with Realm

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

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

这些 API 产生 Json 响应消息,我使用 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
}

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

    @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。

当我保留这些消息时,_abstract 始终为 null,因为 Json 和 Java 字段名称不匹配。

Realm 是否有任何方法可以解决这个问题并仍然使用 createAllFromJson?

或者我是否必须使用 Jackson 或 GS​​ON 将 Json 消息转换为 Java 对象才能保留响应数据?

尝试使用@SerializedName 注释

@SerializedName("abstract")  
private String _abstract;

这个注解属于googlegson注解包,所以可能需要添加gson依赖

https://github.com/realm/realm-java/issues/1470

中提到了一个解决方法

在解决这个问题之前,我已经在我的应用程序中做了一个解决方法,假设我有 Chat.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方法将class的每个Gson SerializedName映射到Realm记录的相应名称。

并且 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);
    }
});