简体   繁体   English

反序列化递归嵌套对象的 json

[英]Deserialize json of recursive nested objects

I am trying to deserialize json like this using gson and then insert it into DB using Room but unsuccessfully:我正在尝试使用 gson 像这样反序列化 json,然后使用 Room 将其插入 DB 但未成功:

[
  {
    "id": 1,
    "name": "category1",
    "categories": [
      {
        "id": 2,
        "name": "category2",
        "count": 321
      },
      {
        "id": 3,
        "name": "category3",
        "categories": [
          {
            "id": 4,
            "name": "category4",
            "count": 20
          },
          {
            "id": 5,
            "name": "category5",
            "count": 205
          },
          {
            "id": 6,
            "name": "category6",
            "count": 85
          }
        ]
      }
    ]
  }
]

Category object should contain:类别对象应包含:

  • id (unique, required) id(唯一,必填)
  • name (required)姓名(必填)
  • parent_id parent_id
  • count (content size if no child items)计数(如果没有子项,则内容大小)

Please help me to recursively parse this and insert into the db.请帮我递归解析这个并插入到数据库中。

What you need to do is have classes that reflect the JSON so that you can then extract the data.您需要做的是拥有反映 JSON 的类,以便您随后可以提取数据。 From those classes you can then insert the data.然后,您可以从这些类中插入数据。

Inspecting the json you have provided then you have:-检查您提供的 json,然后您有:-

  1. an array of what could be MasterCategories, which has可能是 MasterCategories 的数组,其中有
  2. an array of Categories, each of which can have一个类别数组,每个类别可以有
  3. an array of Categories.一个类别数组。

However, you appear to want to save everything according to :-但是,您似乎想根据以下内容保存所有内容:-

Category object should contain: id (unique, required) name (required) parent_id count (content size if no child items)类别对象应包含: id(唯一,必需) name(必需) parent_id 计数(如果没有子项,则内容大小)

as a Category.作为一个类别。

So with that in mind the main class would be Category (into which you want to store all 3 types (MainCategory, Category and the categories within a Category))因此,考虑到这一点,主类将是 Category(您要在其中存储所有 3 种类型(MainCategory、Category 和 Category 中的类别))

So first a MainCategory class:-所以首先是一个MainCategory类:-

class MasterCategory {
   private long id;
   private String name;
   private List<Category> categories;

   public long getId() {
      return id;
   }

   public void setId(long id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public List<Category> getCategories() {
      return categories;
   }

   public void setCategories(List<Category> categories) {
      this.categories = categories;
   }
}

and then second a Category class which will also be the class used to define the table in the database.然后是一个Category类,它也将是用于定义数据库中的表的类。 This could be:-这可能是:-

@Entity
class Category {
    @PrimaryKey
    private Long id = null;
    private String name;
    private long count;
    private Long parent = null;
    @Ignore
    private List<Category> categories = null;

    Category(){}
    @Ignore
    Category(Long id, String name, long count,Long parent, List<Category> categories) {
        this.id = id;
        this.name = name;
        this.count = count;
        this.parent = parent;
        this.categories = categories;
    }
    @Ignore
    Category(Long id, String name, long count, Long parent) {
        this.id = id;
        this.name = name;
        this.count = count;
        this.parent = parent;
        this.categories = null;
    }

    public long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getCount() {
        return count;
    }

    public void setCount(long count) {
        this.count = count;
    }

    public List<Category> getCategories() {
        return categories;
    }

    public void setCategories(List<Category> categories) {
        this.categories = categories;
    }

    public Long getParent() {
        return parent;
    }

    public void setParent(Long parent) {
        this.parent = parent;
    }
}
  • you may wish to study this and reference the appropriate annotations您不妨研究一下并参考适当的注释

To support database access you have an @Dao annotated class CategoryDao eg (sufficient to demonstrate i.ee. store and retrieve):-为了支持数据库访问,您有一个 @Dao 注释类CategoryDao例如(足以证明即存储和检索):-

@Dao
abstract class CategoryDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract long insert(Category category);
    @Query("SELECT * FROM category")
    abstract List<Category> getAllCategories();
}

To combine all of the above, from a database aspect, you have an @Database annotated class TheDatabase eg :-要结合以上所有内容,从数据库方面来看,您有一个 @Database 注释类TheDatabase例如:-

@Database(entities = {Category.class}, exportSchema = false, version = TheDatabase.DATABASE_VERSION)
abstract class TheDatabase extends RoomDatabase {
   public static final int DATABASE_VERSION = 1;
   public static final String DATABASE_NAME = "the_database.db";

   abstract CategoryDao getCategoryDao();

   private volatile static TheDatabase instance = null;
   public static TheDatabase getInstance(Context context) {
      if (instance == null) {
         instance = Room.databaseBuilder(context,TheDatabase.class,DATABASE_NAME)
                 .allowMainThreadQueries()
                 .build();
      }
      return instance;
   }
}
  • note that for convenience and brevity .allowMainThreadQueries has been coded (so the main thread can be used to demonstrate)注意,为了方便和简洁,已经对.allowMainThreadQueries进行了编码(所以可以使用主线程来演示)

Last to actually demonstrate an activity that will take your JSON, store all three types (Master,Category and Categories) as a row, with the appropriate parent (ie Categories will have the respective MasterCategory id as the parent, categories within a Category will have the Category's id as the parent).最后实际演示一个将采用 JSON 的活动,将所有三种类型(主、类别和类别)存储为一行,并带有适当的父级(即类别将具有各自的 MasterCategory id 作为父级,类别中的类别将具有类别的 id 作为父级)。

As MasterCategory has no count the count will be 0.由于 MasterCategory 没有计数,计数将为 0。

For the demo the gson library as per implementation 'com.google.code.gson:gson:2.9.0' has been used.对于演示,已使用按照implementation 'com.google.code.gson:gson:2.9.0'的 gson 库。 This allows the pretty simple getMasterCategoryListFromJSON method, which converts the jSON to a MasterCategory array.这允许使用非常简单的getMasterCategoryListFromJSON方法,该方法将 jSON 转换为 MasterCategory 数组。

The other core method is insertCategoriesFromMasterCategoryArray .另一个核心方法是insertCategoriesFromMasterCategoryArray This takes a MasterCategory[] and inserts Category rows for all three levels/types.这需要一个 MasterCategory[] 并为所有三个级别/类型插入类别行。 It returns a long[] of the inserted id's OR if an insert was IGNORED if there was a conflict (duplicate) then it will store -1 to indicate.它返回插入的 id 的 long[] 或如果插入被忽略,如果存在冲突(重复),那么它将存储 -1 以表示。

So MainActivity :-所以MainActivity :-

public class MainActivity extends AppCompatActivity {

    String base = "[" +
            "  {" +
            " id: 1," +
            "    \"name\": \"category1\"," +
            "    \"categories\": [" +
            "      {" +
            "        \"id\": 2," +
            "        \"name\": \"category2\"," +
            "        \"count\": 321" +
            "      }," +
            "      {" +
            "        \"id\": 3," +
            "        \"name\": \"category3\"," +
            "        \"categories\": [" +
            "          {" +
            "            \"id\": 4," +
            "            \"name\": \"category4\"," +
            "            \"count\": 20" +
            "          }," +
            "          {" +
            "            \"id\": 5," +
            "            \"name\": \"category5\"," +
            "            \"count\": 205" +
            "          }," +
            "          {" +
            "            \"id\": 6," +
            "            \"name\": \"category6\"," +
            "            \"count\": 85" +
            "          }" +
            "        ]" +
            "      }" +
            "    ]" +
            "  }" +
            "]";
    TheDatabase db;
    CategoryDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        db = TheDatabase.getInstance(this);
        dao = db.getCategoryDao();

        MasterCategory[] mlist = getMasterCategoryListFromJSON(base);
        for (MasterCategory m: mlist) {
            Log.d("CATINFO","ID=" + m.getId() + " NAME=" + m.getName() + " it has " + m.getCategories().size() + " categories" );
        }
        long[] insertResult = insertCategoriesFromMasterCategoryArray(getMasterCategoryListFromJSON(base));
        for(Category c: dao.getAllCategories()) {
            Log.d("CATINFO", "ID = " + c.getId() + " NAME = " + c.getName() + " COUNT = " + c.getCount() + " PARENT = " + c.getParent());
        }
    }

    private MasterCategory[] getMasterCategoryListFromJSON(String json) {
        return new Gson().fromJson(json,MasterCategory[].class);
    }

    public long[] insertCategoriesFromMasterCategoryArray(MasterCategory[] mclist) {
        ArrayList<Long> rv = new ArrayList<>();
        Long currentMasterId = 0L;
        Long currentCategoryId = 0L;
        for (MasterCategory mc: mclist) {
            currentMasterId = dao.insert(new Category(mc.getId(),mc.getName(),0,null));
            rv.add(currentMasterId);
            for (Category c: mc.getCategories()) {
                c.setParent(currentMasterId);
                currentCategoryId = dao.insert(new Category(c.getId(),c.getName(),c.getCount(),c.getParent()));
                rv.add(currentCategoryId);
                if (c.getCategories() != null) {
                    for (Category sc : c.getCategories()) {
                        rv.add(dao.insert(new Category(sc.getId(), sc.getName(), sc.getCount(), currentCategoryId)));
                    }
                }
            }
        }
        long[] actualReturnValue = new long[rv.size()];
        for (int i = 0; i < rv.size(); i++) {
            actualReturnValue[i] = rv.get(i);
        }
        return actualReturnValue;
    }
}

This, when run (it's only a demo and therefore intended to be run once) it outputs the following to the log:-这在运行时(它只是一个演示,因此打算运行一次)它将以下内容输出到日志中:-

D/CATINFO: ID=1 NAME=category1 it has 2 categories


D/CATINFO: ID = 1 NAME = category1 COUNT = 0 PARENT = null
D/CATINFO: ID = 2 NAME = category2 COUNT = 321 PARENT = 1
D/CATINFO: ID = 3 NAME = category3 COUNT = 0 PARENT = 1
D/CATINFO: ID = 4 NAME = category4 COUNT = 20 PARENT = 3
D/CATINFO: ID = 5 NAME = category5 COUNT = 205 PARENT = 3
D/CATINFO: ID = 6 NAME = category6 COUNT = 85 PARENT = 3

Using App Inspection then the database is :-使用 App Inspection 然后数据库是:-

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM