java嵌套对象_java-解析包含多个嵌套对象的JSON对象,而不为每个嵌套对象创建类...

我在Android中使用GSON解析JSON对象,该对象的一部分包含多个嵌套对象,这些对象包含所有相同的字段.例如,JSON结构看起来与此类似:

{

"name": "nestedJSONExample",

"divisions": {

"division1": {

"id": string

"name": string,

"alsoKnownAs": [

string

],

}

"division2": {

"id": string

"name": string,

"alsoKnownAs": [

string

],

}

...

"division99" {

"id": string

"name": string,

"alsoKnownAs": [

string

],

}

}

}

在此示例中,所有“ division ##”嵌套对象都包含所有相同的字段,是否可以在不为每个“ division ##”对象创建模型类的情况下将此JSON解析为Java类?

即我可以创建如下的Java结构吗?

divisions.division##.id

不必为每个部门划分班级?

解决方法:

您似乎有些困惑:您不需要为每个Division ##节点使用一个映射类,因为无论属性名称如何,您都可以多次重用一个类.关于您喜欢的方式,您可能需要从零到两个自定义映射类:

> 0个自定义映射类(如果自行遍历已解析的JSON对象);

> 1个自定义映射类,如果应用高级解析技术并将映射与类型适配器或JSON对象组合在一起;

> 2个自定义映射类,用于精确映射.

下面的示例使用Java 8语言功能和Java 8 Stream API编写,但是可以轻松地用Java 6重写.下面的JSON常量只是带有以下JSON文档的字符串:

{

"name": "nestedJSONExample",

"divisions": {

"division1": {"id": "id1", "name": "name1", "alsoKnownAs": ["alsoKnownAs1A"]},

"division2": {"id": "id2", "name": "name2", "alsoKnownAs": ["alsoKnownAs2A"]},

"division3": {"id": "id3", "name": "name3", "alsoKnownAs": ["alsoKnownAs3A"]},

"division4": {"id": "id4", "name": "name4", "alsoKnownAs": ["alsoKnownAs4A"]},

"division5": {"id": "id5", "name": "name5", "alsoKnownAs": ["alsoKnownAs5A"]},

"division6": {"id": "id6", "name": "name6", "alsoKnownAs": ["alsoKnownAs6A"]}

}

}

没有映射

JsonElement是一个内置的Gson类,表示任何JSON元素.结合JsonElement类及其子类元素,Gson可以构建一个反映给定JSON文档结构的JSON树.因此,仅从根开始遍历就足够了.

final Gson gson = new Gson();

final List ids = gson.fromJson(JSON, JsonElement.class)

.getAsJsonObject()

.get("divisions") // get the divisions property

.getAsJsonObject()

.entrySet() // and traverse its key/value pairs

.stream()

.map(Entry::getValue) // discarding the keys

.map(JsonElement::getAsJsonObject)

.map(jo -> jo.get("id")) // take the id property from the every `division` object

.map(JsonElement::getAsJsonPrimitive)

.map(JsonPrimitive::getAsString)

.collect(toList());

System.out.println(ids);

精确映射

在这里,您可能只需要两个映射类来描述JSON对象之间的关系.除法节点可以只是一个包含任意键和除法值的Map.

final class OuterWithMap {

//String name;

Map divisions;

}

final class Division {

String id;

//String name;

//List alsoKnownAs;

}

final Gson gson = new Gson();

final List ids = gson.fromJson(JSON, OuterWithMap.class)

.divisions

.values() // use map values only ignoring the keys

.stream()

.map(d -> d.id)

.collect(toList());

System.out.println(ids);

不完全对应

这是最复杂的方法,它显示了使用Gson解析JSON并将给定JSON文档映射到映射类的高级技术可能无法反映真实结构,因此可以即时进行转换.

final class OuterWithList {

//String name;

@JsonAdapter(NoKeysTypeAdapterFactory.class)

List divisions;

}

final class NoKeysTypeAdapterFactory

implements TypeAdapterFactory {

// No accessible constructor needed - Gson can instantiate it itself

private NoKeysTypeAdapterFactory() {

}

@Override

public TypeAdapter create(final Gson gson, final TypeToken typeToken) {

// Is it a list?

if ( List.class.isAssignableFrom(typeToken.getRawType()) ) {

// Try to determine the list element type

final Type elementType = getElementType(typeToken.getType());

// And create a custom type adapter instance bound to the specific list type

@SuppressWarnings("unchecked")

final TypeAdapter typeAdapter = (TypeAdapter) getNoKeysTypeAdapter(gson, elementType);

return typeAdapter;

}

// Otherwise just tell Gson try to find another appropriate parser

return null;

}

private static Type getElementType(final Type type) {

// Is it a generic type with type parameters?

if ( type instanceof ParameterizedType ) {

final ParameterizedType parameterizedType = (ParameterizedType) type;

// If yes, then just take the first type argument since java.util.List can only one type

return parameterizedType.getActualTypeArguments()[0];

}

// Otherwise java.lang.Object due to either Java generics type erasure or raw types usage

return Object.class;

}

}

final class NoKeysTypeAdapter

extends TypeAdapter> {

private final Gson gson;

private final Type elementType;

private NoKeysTypeAdapter(final Gson gson, final Type elementType) {

this.gson = gson;

this.elementType = elementType;

}

static TypeAdapter> getNoKeysTypeAdapter(final Gson gson, final Type elementType) {

return new NoKeysTypeAdapter<>(gson, elementType);

}

@Override

public void write(final JsonWriter out, final List value) {

throw new UnsupportedOperationException();

}

@Override

public List read(final JsonReader in)

throws IOException {

final List list = new ArrayList<>();

// Make sure that the next JSON stream token is `{`

in.beginObject();

// Read until the object ends

while ( in.peek() != END_OBJECT ) {

// Ignore the found JSON object property name

in.nextName();

// And delegate the property value parsing to a downstream parser

final E element = gson.fromJson(in, elementType);

list.add(element);

}

// Make sure that the JSON stream is finished with the `}` token

in.endObject();

return list;

}

}

使用特殊的查询库

有一些像JsonPath这样的库可以使JSON文档的查询更加容易. JsonPath可以在没有Gson的情况下工作,但是,据我了解,它使用另一个JSON解析库,并且不解析JSON本身(但我不知道它的实际情况).使用示例:

final JsonPath jsonPath = JsonPath.compile("$.divisions.*.id");

final List ids = jsonPath.read(JSON)

.stream()

.map(o -> (String) o)

.collect(toList());

System.out.println(ids);

上面所有四个示例均具有以下输出:

[id1, id2, id3, id4, id5, id6]

标签:gson,json,java,android

来源: https://codeday.me/bug/20191026/1934690.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值