反序列化 json 递归嵌套对象

Deserialize json of recursive nested objects

我正在尝试使用 gson 像这样反序列化 json,然后使用 Room 将其插入数据库但未成功:

[
  {
    "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
          }
        ]
      }
    ]
  }
]

类别对象应包含:

请帮我递归解析并插入数据库。

您需要做的是让 classes 反映 JSON,这样您就可以提取数据。然后,您可以从这些 classes 中插入数据。

检查您提供的 json 然后您有:-

  1. 可能是 MasterCategories 的数组,其中有
  2. 类别数组,每个类别可以有
  3. 一组类别。

但是,您似乎想要根据 :-

保存所有内容

Category object should contain: id (unique, required) name (required) parent_id count (content size if no child items)

作为类别。

考虑到这一点,主要 class 将是类别(您要将所有 3 种类型(MainCategory、类别和类别中的类别)存储到其中)

所以首先是 MainCategory class:-

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;
   }
}

然后是第二个 Category class,这也是用于在数据库中定义 table 的 class。这可能是:-

@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;
    }
}
  • 您不妨研究一下并参考适当的注释

为了支持数据库访问,您有一个带注释的@Dao class CategoryDao 例如(足以证明i.ee。存储和检索):-

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

为了结合以上所有内容,从数据库方面来看,您有一个带注释的@Database class 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;
   }
}
  • 注意为了方便和简洁.allowMainThreadQueries已经编码(所以可以用主线程来演示)

最后一个实际演示的 activity 将采用您的 JSON,将所有三种类型(Master、Category 和 Categories)存储为一行,并具有适当的父级(即类别将具有各自的 MasterCategory id 作为父级,类别中的类别将以类别的 id 作为父级)。

由于 MasterCategory 没有计数,因此计数将为 0。

对于演示,已使用 implementation 'com.google.code.gson:gson:2.9.0' 中的 gson 库。这允许非常简单的 getMasterCategoryListFromJSON 方法,它将 jSON 转换为 MasterCategory 数组。

另一个核心方法是insertCategoriesFromMasterCategoryArray。这需要一个 MasterCategory[] 并为所有三个 levels/types 插入类别行。它 returns 插入的 id 的 long[] 或如果插入被忽略,如果存在冲突(重复),那么它将存储 -1 以指示。

所以 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;
    }
}

这个,当运行(它只是一个演示,因此打算运行一次)它输出以下到日志:-

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

使用 App Inspection 然后数据库是:-