使用杰克逊解析递归嵌套字段
parse recursive nested field using jackson
我有下面的 JSON,我需要从中制作一个 Map<String, String>
。下面JSON,我只有三个级别的parentCategory
,但总的来说可以多一些,也可以少一些。
- 我的地图的键是
79720
,即 categories
部分的 id
,值应是 10987
,即最后一个 [=] 的 id
13=]。
现在我可以在其中嵌套 parentCategory
,所以我在为此制作 POJO 时遇到了问题。我可以有一个级别 parentCategory
或者我可以在每个 parentCategory
中嵌套 parentCategory
我总是需要获取最后一个 parentCategory
.
的 id
因此,我通过转至 jsonschema2pojo 并提供我的 JSON 为此创建了一个 POJO,它生成了我需要的所有文件。通过下面的JSON,它为parentCategory
字段创建了三个类 这样的ParentCategory
、ParentCategory_
和ParentCategory__
。现在,因为我不知道我有多少 parentCategory
级别,所以我不确定为它们生成 POJO 并为最后 parentCategory
提取 id
字段的最佳方法是什么。有没有办法使用 Jackson 做到这一点?
我必须阅读 POJO 中的所有这些数据,因为我也在阅读所有其他字段。
{
"paginationResponse": {
"pageNumber": 1,
"entriesPerPage": 200,
"totalPages": 3
},
"listings": [
{
"categories": [
{
"id": "79720",
"name": "Sunglasses",
"localizedName": "Sunglasses",
"level": 4,
"leafCategory": true,
"parentCategory": {
"id": "394",
"name": "Sunglasses & Fashion Eyewear",
"localizedName": "Sunglasses & Fashion Eyewear",
"level": 3,
"leafCategory": false,
"parentCategory": {
"id": "2340",
"name": "Men's Accessories",
"localizedName": "Men's Accessories",
"level": 2,
"leafCategory": false,
"parentCategory": {
"id": "10987",
"name": "Clothing, Shoes & Accessories",
"localizedName": "Clothing, Shoes & Accessories",
"level": 1,
"leafCategory": false
}
}
}
}
],
"processlisting": {
....
},
"processlistingmetainfo": {
...
},
"processlistingproperties": [
{
"propertyName": "item_url",
"propertyValues": [
{
"stringValue": "url"
}
]
},
{
"propertyName": "listing_site_id",
"propertyValues": [
{
"stringValue": "0"
}
]
}
]
}
],
"total": 100
}
注意:我无法控制此 JSON 结构,因为它不属于我们所有,因此根本无法更改 JSON 结构。
下面是 ParentCategory
的三个 类 是在上面 JSON 的基础上生成的,但通常我可以有多个 ParentCategory
级别,但我没有事先知道。
public class ParentCategory {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
@JsonProperty("localizedName")
private String localizedName;
@JsonProperty("level")
private long level;
@JsonProperty("leafCategory")
private boolean leafCategory;
@JsonProperty("parentCategory")
private ParentCategory_ parentCategory;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
....
}
public class ParentCategory_ {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
@JsonProperty("localizedName")
private String localizedName;
@JsonProperty("level")
private long level;
@JsonProperty("leafCategory")
private boolean leafCategory;
@JsonProperty("parentCategory")
private ParentCategory__ parentCategory;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
...
}
public class ParentCategory__ {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
@JsonProperty("localizedName")
private String localizedName;
@JsonProperty("level")
private long level;
@JsonProperty("leafCategory")
private boolean leafCategory;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
...
}
一般来说 - 检索特定 JSON 属性的最佳工具是 Json-Path,它提供了丰富的查询语言来搜索 JSON 树。
关于题目,需要检索两个不相关的属性,所以需要对JSON树进行两次扫描。这个问题没有指定如何读取输入,所以也许可以将整个输入流读入一个字符串。
下面是检索这两个属性所需查询的代码。无论 parentCategory
级别的数量如何,这都将起作用。诀窍是最后一个 object 是唯一一个没有 child parentCategory
.
我已经在解释查询文本的代码中添加了注释
String categoryIdJsonPath =
"$" + // start from tree root
".listings[0]" + // get listings array's first (only) object
".categories[0]" + // get categories array's first (only) object
".id"; // get id property
String lastParentIdJsonPath =
"$" + // start from tree root
".listings[0]" + // get listings array's first (only) object
".categories[0]" + // get categories array's first (only) object
"..parentCategory" + // do deep scan for all nested parentCategory objects
"[?(!(@.parentCategory))]" + // filter by the object that does NOT have parentCategory property
".id"; // get id property
try {
// read the whole input so it can be scanned twice
String jsonInput = new String(Files.readAllBytes(Paths.get("C://temp/test.json")), Charset.forName("UTF-8"));
String categoryId = JsonPath.read(jsonInput, categoryIdJsonPath);
System.out.println(categoryId);
// return type is always List when deep scan is requested
List<String> lastParent = JsonPath.read(jsonInput, lastParentIdJsonPath);
System.out.println(lastParent.get(0));
} catch (Exception e) {
e.printStackTrace();
}
我有下面的 JSON,我需要从中制作一个 Map<String, String>
。下面JSON,我只有三个级别的parentCategory
,但总的来说可以多一些,也可以少一些。
- 我的地图的键是
79720
,即categories
部分的id
,值应是10987
,即最后一个 [=] 的id
13=]。
现在我可以在其中嵌套 parentCategory
,所以我在为此制作 POJO 时遇到了问题。我可以有一个级别 parentCategory
或者我可以在每个 parentCategory
中嵌套 parentCategory
我总是需要获取最后一个 parentCategory
.
因此,我通过转至 jsonschema2pojo 并提供我的 JSON 为此创建了一个 POJO,它生成了我需要的所有文件。通过下面的JSON,它为parentCategory
字段创建了三个类 这样的ParentCategory
、ParentCategory_
和ParentCategory__
。现在,因为我不知道我有多少 parentCategory
级别,所以我不确定为它们生成 POJO 并为最后 parentCategory
提取 id
字段的最佳方法是什么。有没有办法使用 Jackson 做到这一点?
我必须阅读 POJO 中的所有这些数据,因为我也在阅读所有其他字段。
{
"paginationResponse": {
"pageNumber": 1,
"entriesPerPage": 200,
"totalPages": 3
},
"listings": [
{
"categories": [
{
"id": "79720",
"name": "Sunglasses",
"localizedName": "Sunglasses",
"level": 4,
"leafCategory": true,
"parentCategory": {
"id": "394",
"name": "Sunglasses & Fashion Eyewear",
"localizedName": "Sunglasses & Fashion Eyewear",
"level": 3,
"leafCategory": false,
"parentCategory": {
"id": "2340",
"name": "Men's Accessories",
"localizedName": "Men's Accessories",
"level": 2,
"leafCategory": false,
"parentCategory": {
"id": "10987",
"name": "Clothing, Shoes & Accessories",
"localizedName": "Clothing, Shoes & Accessories",
"level": 1,
"leafCategory": false
}
}
}
}
],
"processlisting": {
....
},
"processlistingmetainfo": {
...
},
"processlistingproperties": [
{
"propertyName": "item_url",
"propertyValues": [
{
"stringValue": "url"
}
]
},
{
"propertyName": "listing_site_id",
"propertyValues": [
{
"stringValue": "0"
}
]
}
]
}
],
"total": 100
}
注意:我无法控制此 JSON 结构,因为它不属于我们所有,因此根本无法更改 JSON 结构。
下面是 ParentCategory
的三个 类 是在上面 JSON 的基础上生成的,但通常我可以有多个 ParentCategory
级别,但我没有事先知道。
public class ParentCategory {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
@JsonProperty("localizedName")
private String localizedName;
@JsonProperty("level")
private long level;
@JsonProperty("leafCategory")
private boolean leafCategory;
@JsonProperty("parentCategory")
private ParentCategory_ parentCategory;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
....
}
public class ParentCategory_ {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
@JsonProperty("localizedName")
private String localizedName;
@JsonProperty("level")
private long level;
@JsonProperty("leafCategory")
private boolean leafCategory;
@JsonProperty("parentCategory")
private ParentCategory__ parentCategory;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
...
}
public class ParentCategory__ {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
@JsonProperty("localizedName")
private String localizedName;
@JsonProperty("level")
private long level;
@JsonProperty("leafCategory")
private boolean leafCategory;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
...
}
一般来说 - 检索特定 JSON 属性的最佳工具是 Json-Path,它提供了丰富的查询语言来搜索 JSON 树。
关于题目,需要检索两个不相关的属性,所以需要对JSON树进行两次扫描。这个问题没有指定如何读取输入,所以也许可以将整个输入流读入一个字符串。
下面是检索这两个属性所需查询的代码。无论 parentCategory
级别的数量如何,这都将起作用。诀窍是最后一个 object 是唯一一个没有 child parentCategory
.
我已经在解释查询文本的代码中添加了注释
String categoryIdJsonPath =
"$" + // start from tree root
".listings[0]" + // get listings array's first (only) object
".categories[0]" + // get categories array's first (only) object
".id"; // get id property
String lastParentIdJsonPath =
"$" + // start from tree root
".listings[0]" + // get listings array's first (only) object
".categories[0]" + // get categories array's first (only) object
"..parentCategory" + // do deep scan for all nested parentCategory objects
"[?(!(@.parentCategory))]" + // filter by the object that does NOT have parentCategory property
".id"; // get id property
try {
// read the whole input so it can be scanned twice
String jsonInput = new String(Files.readAllBytes(Paths.get("C://temp/test.json")), Charset.forName("UTF-8"));
String categoryId = JsonPath.read(jsonInput, categoryIdJsonPath);
System.out.println(categoryId);
// return type is always List when deep scan is requested
List<String> lastParent = JsonPath.read(jsonInput, lastParentIdJsonPath);
System.out.println(lastParent.get(0));
} catch (Exception e) {
e.printStackTrace();
}