反序列化 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
}
]
}
]
}
]
类别对象应包含:
- id(唯一,必填)
- 姓名(必填)
- parent_id
- 计数(如果没有子项则内容大小)
请帮我递归解析并插入数据库。
您需要做的是让 classes 反映 JSON,这样您就可以提取数据。然后,您可以从这些 classes 中插入数据。
检查您提供的 json 然后您有:-
- 可能是 MasterCategories 的数组,其中有
- 类别数组,每个类别可以有
- 一组类别。
但是,您似乎想要根据 :-
保存所有内容
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 然后数据库是:-
我正在尝试使用 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
}
]
}
]
}
]
类别对象应包含:
- id(唯一,必填)
- 姓名(必填)
- parent_id
- 计数(如果没有子项则内容大小)
请帮我递归解析并插入数据库。
您需要做的是让 classes 反映 JSON,这样您就可以提取数据。然后,您可以从这些 classes 中插入数据。
检查您提供的 json 然后您有:-
- 可能是 MasterCategories 的数组,其中有
- 类别数组,每个类别可以有
- 一组类别。
但是,您似乎想要根据 :-
保存所有内容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 然后数据库是:-